From: Kern Sibbald Date: Fri, 28 Nov 2003 14:59:02 +0000 (+0000) Subject: Implement saving last 10 jobs run X-Git-Tag: Release-7.0.0~9905 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=0f7f41be668f7a9dfc832df968aa9db034323569;p=bacula%2Fbacula Implement saving last 10 jobs run git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@816 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index 596b22bb8c..8aa46fd83c 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -57,18 +57,24 @@ For 1.33 Testing/Documentation: it with the catalog database. - Document Dan's new --with-dir-user, ... options. - For 1.33 +- Change "create_media_record in bscan to use Archive instead of Full. - Implement RestoreJobRetention? Maybe better "JobRetention" in a Job, which would take precidence over the Catalog "JobRetention". - Implement Label Format in Add and Label console commands. -- Possibly up network buffers to 65K. -- Keep last 5 or 10 completed jobs and show them in a similar list. -- Make a Running Jobs: output similar to current Scheduled Jobs: +- Possibly up network buffers to 65K. Put on variable. +- Put email tape request delays on one or more variables. User wants + to cancel the job after a certain time interval. Maximum Mount Wait? + Job, Client, Device, Pool, or Volume? After 1.33: +- Each DVD-RAM disk would be a volume, just like each tape is + a volume. It's a 4.7GB media with random access, but there's nothing about + it that I can see that makes it so different than a tape fromĀ  bacula's + perspective. Why couldn't I back up to a bare floppy as a volume (ignoring + the media capacity?) - Make dev->file and dev->block_num signed integers so that -1 can - be an invalid value. + be an invalid value which happens with BSR. - Create VolAddr for disk files in place of VolFile and VolBlock. This is needed to properly specify ranges. - Print bsmtp output to job report so that problems will be seen. @@ -927,3 +933,6 @@ Done: (see kernsdone for more) - Implement autochanger testing in btape "test" command. - Implement lmark to list everyfile marked. - Make mark/unmark report how many files marked/unmarked. +- Keep last 5 or 10 completed jobs and show them in a similar list. +- Make a Running Jobs: output similar to current Scheduled Jobs: + diff --git a/bacula/platforms/redhat/bacula.spec.in b/bacula/platforms/redhat/bacula.spec.in index 6c604039d6..d8fba455fa 100644 --- a/bacula/platforms/redhat/bacula.spec.in +++ b/bacula/platforms/redhat/bacula.spec.in @@ -274,7 +274,6 @@ cp rescue/linux/backup.etc.list $RPM_BUILD_ROOT/etc/bacula/rescue/ cp rescue/linux/format_floppy $RPM_BUILD_ROOT/etc/bacula/rescue/ cp rescue/linux/getdiskinfo $RPM_BUILD_ROOT/etc/bacula/rescue/ cp rescue/linux/make_rescue_disk $RPM_BUILD_ROOT/etc/bacula/rescue/ -cp rescue/linux/make_static_bacula $RPM_BUILD_ROOT/etc/bacula/rescue/ cp rescue/linux/restore_bacula $RPM_BUILD_ROOT/etc/bacula/rescue/ cp rescue/linux/restore_etc $RPM_BUILD_ROOT/etc/bacula/rescue/ cp rescue/linux/run_grub $RPM_BUILD_ROOT/etc/bacula/rescue/ @@ -455,7 +454,6 @@ chmod 0755 /usr/sbin/gnome-console %attr(0754,root,root) /etc/bacula/rescue/format_floppy %attr(0754,root,root) /etc/bacula/rescue/getdiskinfo %attr(0754,root,root) /etc/bacula/rescue/make_rescue_disk -%attr(0754,root,root) /etc/bacula/rescue/make_static_bacula %attr(0754,root,root) /etc/bacula/rescue/restore_bacula %attr(0754,root,root) /etc/bacula/rescue/restore_etc %attr(0754,root,root) /etc/bacula/rescue/run_grub @@ -499,6 +497,8 @@ rm -f /etc/bacula/rescue/sfdisk rm -rf /etc/bacula/rescue/diskinfo/* %changelog +* Tue Nov 25 2003 D. Scott Barninger +- removed make_static_bacula script from rescue package install * Sun Nov 23 2003 D. Scott Barninger - Added define at top of file for depkgs version - Added rescue sub-package diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index 410cbb5d36..b413042122 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -97,7 +97,6 @@ int main (int argc, char *argv[]) textdomain("bacula-dir"); init_msg(NULL, NULL); /* initialize message handler */ daemon_start_time = time(NULL); - memset(&last_job, 0, sizeof(last_job)); while ((ch = getopt(argc, argv, "c:d:fg:r:stu:v?")) != -1) { switch (ch) { diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 0fcdea6177..4657662a30 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -178,10 +178,10 @@ int restore_cmd(UAContext *ua, char *cmd) return 0; } write_bsr_file(ua, rx.bsr); - bsendmsg(ua, _("\n%u file%s selected to restore.\n\n"), rx.selected_files, + bsendmsg(ua, _("\n%u file%s selected to be restored.\n\n"), rx.selected_files, rx.selected_files==1?"":"s"); } else { - bsendmsg(ua, _("No files selected to restore.\n")); + bsendmsg(ua, _("No files selected to be restored.\n")); free_rx(&rx); return 0; } diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index c9aaede5ba..36410af261 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -34,7 +34,9 @@ extern char my_name[]; extern time_t daemon_start_time; extern struct s_last_job last_job; -static void print_jobs_scheduled(UAContext *ua); +static void list_scheduled_jobs(UAContext *ua); +static void list_running_jobs(UAContext *ua); +static void list_terminated_jobs(UAContext *ua); static void do_storage_status(UAContext *ua, STORE *store); static void do_client_status(UAContext *ua, CLIENT *client); static void do_director_status(UAContext *ua, char *cmd); @@ -190,141 +192,27 @@ static void do_all_status(UAContext *ua, char *cmd) static void do_director_status(UAContext *ua, char *cmd) { - JCR *jcr; - int njobs = 0; - char *msg; - char dt[MAX_TIME_LENGTH], b1[30], b2[30]; - int pool_mem = FALSE; + char dt[MAX_TIME_LENGTH]; bsendmsg(ua, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name, HOST_OS, DISTNAME, DISTVER); bstrftime(dt, sizeof(dt), daemon_start_time); bsendmsg(ua, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs, last_job.NumJobs == 1 ? "" : "s"); - if (last_job.NumJobs > 0) { - char termstat[50]; - - bstrftime(dt, sizeof(dt), last_job.end_time); - bsendmsg(ua, _("Last Job %s finished at %s\n"), last_job.Job, dt); - jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat)); - - bsendmsg(ua, _(" Files=%s Bytes=%s Termination Status=%s\n"), - edit_uint64_with_commas(last_job.JobFiles, b1), - edit_uint64_with_commas(last_job.JobBytes, b2), - termstat); - } - lock_jcr_chain(); - for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) { - if (jcr->JobId == 0) { /* this is us */ - bstrftime(dt, sizeof(dt), jcr->start_time); - bsendmsg(ua, _("Console connected at %s\n"), dt); - free_locked_jcr(jcr); - njobs--; - continue; - } - 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: - msg = (char *) get_pool_memory(PM_FNAME); - Mmsg(&msg, _("is waiting on Client %s"), jcr->client->hdr.name); - pool_mem = TRUE; - break; - case JS_WaitSD: - msg = (char *) get_pool_memory(PM_FNAME); - Mmsg(&msg, _("is waiting on Storage %s"), jcr->store->hdr.name); - pool_mem = TRUE; - 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; - - default: - msg = (char *) get_pool_memory(PM_FNAME); - Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus); - pool_mem = TRUE; - break; - } - /* - * Now report Storage daemon status code - */ - switch (jcr->SDJobStatus) { - case JS_WaitMount: - if (pool_mem) { - free_pool_memory(msg); - pool_mem = FALSE; - } - msg = _("is waiting for a mount request"); - break; - case JS_WaitMedia: - if (pool_mem) { - free_pool_memory(msg); - pool_mem = FALSE; - } - msg = _("is waiting for an appendable Volume"); - break; - case JS_WaitFD: - if (!pool_mem) { - msg = (char *) get_pool_memory(PM_FNAME); - pool_mem = TRUE; - } - Mmsg(&msg, _("is waiting for Client %s to connect to Storage %s"), - jcr->client->hdr.name, jcr->store->hdr.name); - break; - } - bsendmsg(ua, _("JobId %d Job %s %s.\n"), jcr->JobId, jcr->Job, msg); - if (pool_mem) { - free_pool_memory(msg); - pool_mem = FALSE; - } - free_locked_jcr(jcr); - } - unlock_jcr_chain(); - - if (njobs == 0) { - bsendmsg(ua, _("No jobs are running.\n")); - } - print_jobs_scheduled(ua); + /* + * List scheduled Jobs + */ + list_scheduled_jobs(ua); + + /* + * List running jobs + */ + list_running_jobs(ua); + + /* + * List terminated jobs + */ + list_terminated_jobs(ua); bsendmsg(ua, "====\n"); } @@ -445,16 +333,16 @@ static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime, POOL } /* - * Find all jobs to be run this hour - * and the next hour. + * Find all jobs to be run in roughly the + * next 24 hours. */ -static void print_jobs_scheduled(UAContext *ua) +static void list_scheduled_jobs(UAContext *ua) { time_t runtime; RUN *run; JOB *job; + int level, num_jobs = 0; bool hdr_printed = false; - int level; Dmsg0(200, "enter find_runs()\n"); @@ -467,13 +355,240 @@ static void print_jobs_scheduled(UAContext *ua) level = run->level; } if (!hdr_printed) { - hdr_printed = true; prt_runhdr(ua); + hdr_printed = true; } prt_runtime(ua, job, level, runtime, run->pool); + num_jobs++; } } /* end for loop over resources */ UnlockRes(); + if (num_jobs == 0) { + bsendmsg(ua, _("No Scheduled Jobs.\n")); + } else { + bsendmsg(ua, "\n"); + } Dmsg0(200, "Leave find_runs()\n"); } + +static void list_running_jobs(UAContext *ua) +{ + JCR *jcr; + int njobs = 0; + char *msg; + char dt[MAX_TIME_LENGTH]; + char level[10]; + bool pool_mem = false; + + lock_jcr_chain(); + for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) { + if (jcr->JobId == 0) { /* this is us */ + bstrftime(dt, sizeof(dt), jcr->start_time); + bsendmsg(ua, _("Console connected at %s\n"), dt); + njobs--; + } + free_locked_jcr(jcr); + } + if (njobs == 0) { + unlock_jcr_chain(); + bsendmsg(ua, _("No Running Jobs.\n")); + return; + } + njobs = 0; + bsendmsg(ua, _("\nRunning Jobs:\n")); + bsendmsg(ua, _("Level JobId Job Status\n")); + bsendmsg(ua, _("====================================================================\n")); + for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) { + if (jcr->JobId == 0) { /* this is us */ + njobs--; + free_locked_jcr(jcr); + continue; + } + 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: + msg = (char *) get_pool_memory(PM_FNAME); + Mmsg(&msg, _("is waiting on Client %s"), jcr->client->hdr.name); + pool_mem = true; + break; + case JS_WaitSD: + msg = (char *) get_pool_memory(PM_FNAME); + Mmsg(&msg, _("is waiting on Storage %s"), jcr->store->hdr.name); + pool_mem = true; + 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; + + default: + msg = (char *) get_pool_memory(PM_FNAME); + Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus); + pool_mem = true; + break; + } + /* + * Now report Storage daemon status code + */ + switch (jcr->SDJobStatus) { + case JS_WaitMount: + if (pool_mem) { + free_pool_memory(msg); + pool_mem = false; + } + msg = _("is waiting for a mount request"); + break; + case JS_WaitMedia: + if (pool_mem) { + free_pool_memory(msg); + pool_mem = false; + } + msg = _("is waiting for an appendable Volume"); + break; + case JS_WaitFD: + if (!pool_mem) { + msg = (char *) get_pool_memory(PM_FNAME); + pool_mem = true; + } + Mmsg(&msg, _("is waiting for Client %s to connect to Storage %s"), + jcr->client->hdr.name, jcr->store->hdr.name); + 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[4] = 0; + break; + } + + bsendmsg(ua, _("%-4s %6d %-20s %s\n"), + level, + jcr->JobId, + jcr->Job, + msg); + + if (pool_mem) { + free_pool_memory(msg); + pool_mem = false; + } + free_locked_jcr(jcr); + } + unlock_jcr_chain(); + + bsendmsg(ua, "\n"); +} + +static void list_terminated_jobs(UAContext *ua) +{ + char dt[MAX_TIME_LENGTH], b1[30], b2[30]; + char level[10]; + + if (last_job.NumJobs == 0) { + bsendmsg(ua, _("No Terminated Jobs.\n")); + return; + } + lock_last_jobs_list(); + struct s_last_job *je; + bsendmsg(ua, _("\nTerminated Jobs:\n")); + bsendmsg(ua, _("Level Files Bytes Status Finished Name \n")); + bsendmsg(ua, _("====================================================================\n")); + for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) { + char JobName[MAX_NAME_LENGTH]; + char *termstat; + + bstrftime(dt, sizeof(dt), je->end_time); + strcpy(dt+7, dt+9); /* cut century */ + 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 */ + char *p; + for (int i=0; i<3; i++) { + if ((p=strrchr(JobName, '.')) != NULL) { + *p = 0; + } + } + bsendmsg(ua, _("%-4s %8s %12s %-7s %-8s %s\n"), + level, + edit_uint64_with_commas(je->JobFiles, b1), + edit_uint64_with_commas(je->JobBytes, b2), + termstat, + dt, JobName); + } + bsendmsg(ua, "\n"); + unlock_last_jobs_list(); +} diff --git a/bacula/src/dird/ua_tree.c b/bacula/src/dird/ua_tree.c index d914868c53..089eaee403 100644 --- a/bacula/src/dird/ua_tree.c +++ b/bacula/src/dird/ua_tree.c @@ -63,9 +63,9 @@ static struct cmdstruct commands[] = { { N_("help"), helpcmd, _("print help")}, { N_("lsmark"), lsmark, _("list the marked files")}, { N_("ls"), lscmd, _("list current directory")}, - { N_("mark"), markcmd, _("mark file for restoration")}, + { N_("mark"), markcmd, _("mark file to be restored")}, { N_("pwd"), pwdcmd, _("print current working directory")}, - { N_("unmark"), unmarkcmd, _("unmark file for restoration")}, + { N_("unmark"), unmarkcmd, _("unmark file to be restored")}, { N_("?"), helpcmd, _("print help")}, }; #define comsize (sizeof(commands)/sizeof(struct cmdstruct)) @@ -209,7 +209,7 @@ static int set_extract(UAContext *ua, TREE_NODE *node, TREE_CTX *tree, bool extr decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */ /* * If we point to a hard linked file, traverse the tree to - * find that file, and mark it for restoration as well. It + * find that file, and mark it to be restored as well. It * must have the Link we just obtained and the same JobId. */ if (LinkFI) { @@ -260,7 +260,7 @@ static int countcmd(UAContext *ua, TREE_CTX *tree) } } } - bsendmsg(ua, "%d total files. %d marked for restoration.\n", total, num_extract); + bsendmsg(ua, "%d total files. %d marked to be restored.\n", total, num_extract); return 1; } @@ -422,7 +422,7 @@ static int estimatecmd(UAContext *ua, TREE_CTX *tree) } } } - bsendmsg(ua, "%d total files; %d marked for restoration; %s bytes.\n", + bsendmsg(ua, "%d total files; %d marked to be restored; %s bytes.\n", total, num_extract, edit_uint64_with_commas(total_bytes, ec1)); return 1; } diff --git a/bacula/src/filed/filed.c b/bacula/src/filed/filed.c index 1c321e7d7b..aa8dbe07be 100644 --- a/bacula/src/filed/filed.c +++ b/bacula/src/filed/filed.c @@ -99,8 +99,6 @@ int main (int argc, char *argv[]) init_msg(NULL, NULL); daemon_start_time = time(NULL); - memset(&last_job, 0, sizeof(last_job)); - while ((ch = getopt(argc, argv, "c:d:fg:istu:v?")) != -1) { switch (ch) { case 'c': /* configuration file */ diff --git a/bacula/src/filed/status.c b/bacula/src/filed/status.c index c1c6ce1878..806a98d70c 100755 --- a/bacula/src/filed/status.c +++ b/bacula/src/filed/status.c @@ -33,6 +33,12 @@ extern char my_name[]; extern struct s_last_job last_job; extern time_t daemon_start_time; +/* Forward referenced functions */ +static void list_terminated_jobs(void *arg); +static void sendit(char *msg, int len, void *arg); +static char *level_to_str(int level); + + #ifdef HAVE_CYGWIN static int privs = 0; #endif @@ -58,35 +64,47 @@ static void do_status(void sendit(char *msg, int len, void *sarg), void *arg) last_job.NumJobs == 1 ? "" : "s"); sendit(msg, len, arg); #ifdef HAVE_CYGWIN - if (!privs) { - privs = enable_backup_privileges(NULL, 1); + if (debug_level > 0) { + if (!privs) { + privs = enable_backup_privileges(NULL, 1); + } + len = Mmsg(&msg, + _("Priv 0x%x APIs=%sOPT,%sATP,%sLPV,%sGFAE,%sBR,%sBW,%sSPSP\n"), privs, + p_OpenProcessToken?"":"!", + p_AdjustTokenPrivileges?"":"!", + p_LookupPrivilegeValue?"":"!", + p_GetFileAttributesEx?"":"!", + p_BackupRead?"":"!", + p_BackupWrite?"":"!", + p_SetProcessShutdownParameters?"":"!"); + sendit(msg, len, arg); } - len = Mmsg(&msg, - _("Priv 0x%x APIs=%sOPT,%sATP,%sLPV,%sGFAE,%sBR,%sBW,%sSPSP\n"), privs, - p_OpenProcessToken?"":"!", - p_AdjustTokenPrivileges?"":"!", - p_LookupPrivilegeValue?"":"!", - p_GetFileAttributesEx?"":"!", - p_BackupRead?"":"!", - p_BackupWrite?"":"!", - p_SetProcessShutdownParameters?"":"!"); - sendit(msg, len, arg); #endif - if (last_job.NumJobs > 0) { + list_terminated_jobs(arg); + +#ifdef xxx char termstat[30]; + struct s_last_job *je; + lock_last_jobs_list(); + for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) { + bstrftime(dt, sizeof(dt), je->end_time); + len = Mmsg(&msg, _("Last Job %s finished at %s\n"), je->Job, dt); + sendit(msg, len, arg); - bstrftime(dt, sizeof(dt), last_job.end_time); - len = Mmsg(&msg, _("Last Job %s finished at %s\n"), last_job.Job, dt); - sendit(msg, len, arg); + jobstatus_to_ascii(je->JobStatus, termstat, sizeof(termstat)); + len = Mmsg(&msg, _(" Files=%s Bytes=%s Termination Status=%s\n"), + edit_uint64_with_commas(je->JobFiles, b1), + edit_uint64_with_commas(je->JobBytes, b2), + termstat); + sendit(msg, len, arg); + } + unlock_last_jobs_list(); +#endif - jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat)); - len = Mmsg(&msg, _(" Files=%s Bytes=%s Termination Status=%s\n"), - edit_uint64_with_commas(last_job.JobFiles, b1), - edit_uint64_with_commas(last_job.JobBytes, b2), - termstat); - sendit(msg, len, arg); - } + /* + * List running jobs + */ Dmsg0(200, "Begin status jcr loop.\n"); lock_jcr_chain(); for (njcr=NULL; (njcr=get_next_jcr(njcr)); ) { @@ -145,6 +163,84 @@ static void do_status(void sendit(char *msg, int len, void *sarg), void *arg) free_pool_memory(msg); } +static void list_terminated_jobs(void *arg) +{ + char dt[MAX_TIME_LENGTH], b1[30], b2[30]; + char level[10]; + struct s_last_job *je; + char *msg; + + if (last_job.NumJobs == 0) { + msg = _("No Terminated Jobs.\n"); + sendit(msg, strlen(msg), arg); + return; + } + lock_last_jobs_list(); + msg = _("\nTerminated Jobs:\n"); + sendit(msg, strlen(msg), arg); + msg = _("Level Files Bytes Status Finished Name \n"); + sendit(msg, strlen(msg), arg); + msg = _("====================================================================\n"); + sendit(msg, strlen(msg), arg); + for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) { + char JobName[MAX_NAME_LENGTH]; + char *termstat; + char buf[1000]; + + bstrftime(dt, sizeof(dt), je->end_time); + strcpy(dt+7, dt+9); /* cut century */ + 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 */ + char *p; + for (int i=0; i<3; i++) { + if ((p=strrchr(JobName, '.')) != NULL) { + *p = 0; + } + } + bsnprintf(buf, sizeof(buf), _("%-4s %8s %12s %-7s %-8s %s\n"), + level, + edit_uint64_with_commas(je->JobFiles, b1), + edit_uint64_with_commas(je->JobBytes, b2), + termstat, + dt, JobName); + sendit(buf, strlen(buf), arg); + } + sendit("\n", 1, arg); + unlock_last_jobs_list(); +} + + /* * Send to Director */ @@ -173,6 +269,54 @@ int status_cmd(JCR *jcr) } +/* + * Convert Job Level into a string + */ +static char *level_to_str(int level) +{ + char *str; + + switch (level) { + case L_BASE: + str = _("Base"); + case L_FULL: + str = _("Full"); + break; + case L_INCREMENTAL: + str = _("Incremental"); + break; + case L_DIFFERENTIAL: + str = _("Differential"); + break; + case L_SINCE: + str = _("Since"); + break; + case L_VERIFY_CATALOG: + str = _("Verify Catalog"); + break; + case L_VERIFY_INIT: + str = _("Init Catalog"); + break; + case L_VERIFY_VOLUME_TO_CATALOG: + str = _("Volume to Catalog"); + break; + case L_VERIFY_DISK_TO_CATALOG: + str = _("Disk to Catalog"); + break; + case L_VERIFY_DATA: + str = _("Data"); + break; + case L_NONE: + str = " "; + break; + default: + str = _("Unknown Job Level"); + break; + } + return str; +} + + #ifdef HAVE_CYGWIN #include diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 0d6a981882..8a47e2e6c3 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -253,9 +253,11 @@ struct JCR { * info on the last job run. */ struct s_last_job { + dlink link; int NumJobs; int JobType; int JobStatus; + int JobLevel; uint32_t JobId; uint32_t VolSessionId; uint32_t VolSessionTime; @@ -266,7 +268,8 @@ struct s_last_job { char Job[MAX_NAME_LENGTH]; }; -extern struct s_last_job last_job; +extern struct s_last_job last_job; +extern dlist *last_jobs; /* The following routines are found in lib/jcr.c */ diff --git a/bacula/src/lib/jcr.c b/bacula/src/lib/jcr.c index ee884d1634..03c86d08b5 100755 --- a/bacula/src/lib/jcr.c +++ b/bacula/src/lib/jcr.c @@ -33,11 +33,39 @@ extern void timeout_handler(int sig); -struct s_last_job last_job; /* last job run by this daemon */ +struct s_last_job last_job; /* last job run by this daemon */ +dlist *last_jobs; +static int num_last_jobs = 0; +#define MAX_LAST_JOBS 10 static JCR *jobs = NULL; /* pointer to JCR chain */ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +void init_last_jobs_list() +{ + struct s_last_job *job_entry; + last_jobs = new dlist(job_entry, &job_entry->link); + memset(&last_job, 0, sizeof(last_job)); +} + +void term_last_jobs_list() +{ + for (void *je=NULL; (je=last_jobs->next(je)); ) { + free(je); + } + delete last_jobs; +} + +void lock_last_jobs_list() +{ + P(mutex); +} + +void unlock_last_jobs_list() +{ + V(mutex); +} + /* * Create a Job Control Record and link it into JCR chain * Returns newly allocated JCR @@ -59,9 +87,9 @@ JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr) pthread_mutex_init(&(jcr->mutex), NULL); jcr->JobStatus = JS_Created; /* ready to run */ jcr->VolumeName = get_pool_memory(PM_FNAME); - mp_chr(jcr->VolumeName)[0] = 0; + jcr->VolumeName[0] = 0; jcr->errmsg = get_pool_memory(PM_MESSAGE); - mp_chr(jcr->errmsg)[0] = 0; + jcr->errmsg[0] = 0; strcpy(jcr->Job, "*Console*"); /* default */ sigtimer.sa_flags = 0; @@ -124,6 +152,7 @@ static void free_common_jcr(JCR *jcr) last_job.JobFiles = jcr->JobFiles; last_job.JobBytes = jcr->JobBytes; last_job.JobStatus = jcr->JobStatus; + last_job.JobLevel = jcr->JobLevel; last_job.start_time = jcr->start_time; last_job.end_time = time(NULL); break; @@ -183,9 +212,11 @@ void b_free_jcr(char *file, int line, JCR *jcr) void free_jcr(JCR *jcr) { + Dmsg1(200, "Enter free_jcr 0x%x\n", jcr); #endif + struct s_last_job *je; P(mutex); jcr->use_count--; /* decrement use count */ @@ -205,6 +236,16 @@ void free_jcr(JCR *jcr) free_common_jcr(jcr); P(mutex); + /* Keep list of last jobs, but not Console where JobId==0 */ + if (last_job.JobId > 0) { + je = (struct s_last_job *)malloc(sizeof(struct s_last_job)); + memcpy((char *)je, (char *)&last_job, sizeof(last_job)); + last_jobs->append(je); + if (++num_last_jobs > MAX_LAST_JOBS) { + last_jobs->remove(last_jobs->first()); + num_last_jobs--; + } + } close_msg(NULL); /* flush any daemon messages */ V(mutex); Dmsg0(200, "Exit free_jcr\n"); diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 5008b08788..6391df5908 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -160,6 +160,10 @@ init_msg(JCR *jcr, MSGS *msg) DEST *d, *dnew, *temp_chain = NULL; int i, fd; + if (jcr == NULL && msg == NULL) { + init_last_jobs_list(); + } + /* * Make sure we have fd's 0, 1, 2 open * If we don't do this one of our sockets may open @@ -551,6 +555,7 @@ void term_msg() fclose(trace_fd); trace_fd = NULL; } + term_last_jobs_list(); } diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 6c06d15f51..24bd211d24 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -117,6 +117,13 @@ char *edit_utime (utime_t val, char *buf); int is_a_number (const char *num); int is_an_integer (const char *n); +/* jcr.c (most definitions are in src/jcr.h) */ +void init_last_jobs_list(); +void term_last_jobs_list(); +void lock_last_jobs_list(); +void unlock_last_jobs_list(); + + /* lex.c */ LEX * lex_close_file (LEX *lf); LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index ddeee967f9..6991f271b5 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -47,7 +47,8 @@ int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) int i; if (device_is_unmounted(dev)) { - Jmsg(jcr, M_WARNING, 0, _("device is BLOCKED due to user unmount.\n")); + Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"), + dev_name(dev)); } lock_device(dev); block_device(dev, BST_DOING_ACQUIRE); @@ -170,7 +171,8 @@ DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) DEVICE *rtn_dev = NULL; if (device_is_unmounted(dev)) { - Jmsg(jcr, M_WARNING, 0, _("device is BLOCKED due to user unmount.\n")); + Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"), + dev_name(dev)); } lock_device(dev); block_device(dev, BST_DOING_ACQUIRE); diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index 0d13588698..f1b775f6f4 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -44,6 +44,9 @@ extern struct s_last_job last_job; /* Forward referenced functions */ static void send_blocked_status(JCR *jcr, DEVICE *dev); +static void list_terminated_jobs(void *arg); +static void sendit(char *msg, int len, void *arg); +static char *level_to_str(int level); /* @@ -63,7 +66,12 @@ int status_cmd(JCR *jcr) bstrftime(dt, sizeof(dt), daemon_start_time); bnet_fsend(user, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs, last_job.NumJobs == 1 ? "" : "s"); - if (last_job.NumJobs > 0) { + + /* + * List terminated jobs + */ + list_terminated_jobs(user); +#ifdef xxx char termstat[30]; bstrftime(dt, sizeof(dt), last_job.end_time); @@ -74,8 +82,11 @@ int status_cmd(JCR *jcr) edit_uint64_with_commas(last_job.JobFiles, b1), edit_uint64_with_commas(last_job.JobBytes, b2), termstat); - } +#endif + /* + * List devices + */ LockRes(); for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) { for (dev=device->dev; dev; dev=dev->next) { @@ -167,7 +178,7 @@ int status_cmd(JCR *jcr) bnet_fsend(user, _("No jobs running.\n")); } -#ifdef full_status +#ifdef xfull_status bnet_fsend(user, "\n\n"); dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user); #endif @@ -241,3 +252,139 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev) } } + +static void list_terminated_jobs(void *arg) +{ + char dt[MAX_TIME_LENGTH], b1[30], b2[30]; + char level[10]; + struct s_last_job *je; + char *msg; + + if (last_job.NumJobs == 0) { + msg = _("No Terminated Jobs.\n"); + sendit(msg, strlen(msg), arg); + return; + } + lock_last_jobs_list(); + msg = _("\nTerminated Jobs:\n"); + sendit(msg, strlen(msg), arg); + msg = _("Level Files Bytes Status Finished Name \n"); + sendit(msg, strlen(msg), arg); + msg = _("====================================================================\n"); + sendit(msg, strlen(msg), arg); + for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) { + char JobName[MAX_NAME_LENGTH]; + char *termstat; + char buf[1000]; + + bstrftime(dt, sizeof(dt), je->end_time); + strcpy(dt+7, dt+9); /* cut century */ + 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 */ + char *p; + for (int i=0; i<3; i++) { + if ((p=strrchr(JobName, '.')) != NULL) { + *p = 0; + } + } + bsnprintf(buf, sizeof(buf), _("%-4s %8s %12s %-7s %-8s %s\n"), + level, + edit_uint64_with_commas(je->JobFiles, b1), + edit_uint64_with_commas(je->JobBytes, b2), + termstat, + dt, JobName); + sendit(buf, strlen(buf), arg); + } + sendit("\n", 1, arg); + unlock_last_jobs_list(); +} + +/* + * Convert Job Level into a string + */ +static char *level_to_str(int level) +{ + char *str; + + switch (level) { + case L_BASE: + str = _("Base"); + case L_FULL: + str = _("Full"); + break; + case L_INCREMENTAL: + str = _("Incremental"); + break; + case L_DIFFERENTIAL: + str = _("Differential"); + break; + case L_SINCE: + str = _("Since"); + break; + case L_VERIFY_CATALOG: + str = _("Verify Catalog"); + break; + case L_VERIFY_INIT: + str = _("Init Catalog"); + break; + case L_VERIFY_VOLUME_TO_CATALOG: + str = _("Volume to Catalog"); + break; + case L_VERIFY_DISK_TO_CATALOG: + str = _("Disk to Catalog"); + break; + case L_VERIFY_DATA: + str = _("Data"); + break; + case L_NONE: + str = " "; + break; + default: + str = _("Unknown Job Level"); + break; + } + return str; +} + +/* + * Send to Director + */ +static void sendit(char *msg, int len, void *arg) +{ + BSOCK *user = (BSOCK *)arg; + + memcpy(user->msg, msg, len+1); + user->msglen = len+1; + bnet_send(user); +} diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index 96ba176f97..a83e70bd01 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -94,7 +94,6 @@ int main (int argc, char *argv[]) textdomain("bacula-sd"); init_msg(NULL, NULL); daemon_start_time = time(NULL); - memset(&last_job, 0, sizeof(last_job)); /* Sanity checks */ if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) { diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index d9f2cfa40c..5d1eee1c01 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -128,7 +128,7 @@ struct s_res resources[] = { {"storage", store_items, R_STORAGE, NULL}, {"device", dev_items, R_DEVICE, NULL}, {"messages", msgs_items, R_MSGS, NULL}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; @@ -144,82 +144,82 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... return; } sendit(sock, "dump_resource type=%d\n", type); - if (type < 0) { /* no recursion */ + if (type < 0) { /* no recursion */ type = - type; recurse = 0; } switch (type) { - case R_DIRECTOR: - sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name); - break; - case R_STORAGE: - sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n", - res->res_store.hdr.name, NPRT(res->res_store.SDaddr), - res->res_store.SDport, res->res_store.SDDport, - edit_utime(res->res_store.heartbeat_interval, buf)); - break; - case R_DEVICE: - sendit(sock, "Device: name=%s MediaType=%s Device=%s\n", - res->res_dev.hdr.name, - res->res_dev.media_type, res->res_dev.device_name); - sendit(sock, " rew_wait=%d min_bs=%d max_bs=%d\n", - res->res_dev.max_rewind_wait, res->res_dev.min_block_size, - res->res_dev.max_block_size); - sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n", - res->res_dev.max_volume_jobs, res->res_dev.max_volume_files, - res->res_dev.max_volume_size); - sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n", - res->res_dev.max_file_size, res->res_dev.volume_capacity); - strcpy(buf, " "); - if (res->res_dev.cap_bits & CAP_EOF) { - strcat(buf, "CAP_EOF "); - } - if (res->res_dev.cap_bits & CAP_BSR) { - strcat(buf, "CAP_BSR "); - } - if (res->res_dev.cap_bits & CAP_BSF) { - strcat(buf, "CAP_BSF "); - } - if (res->res_dev.cap_bits & CAP_FSR) { - strcat(buf, "CAP_FSR "); - } - if (res->res_dev.cap_bits & CAP_FSF) { - strcat(buf, "CAP_FSF "); - } - if (res->res_dev.cap_bits & CAP_EOM) { - strcat(buf, "CAP_EOM "); - } - if (res->res_dev.cap_bits & CAP_REM) { - strcat(buf, "CAP_REM "); - } - if (res->res_dev.cap_bits & CAP_RACCESS) { - strcat(buf, "CAP_RACCESS "); - } - if (res->res_dev.cap_bits & CAP_AUTOMOUNT) { - strcat(buf, "CAP_AUTOMOUNT "); - } - if (res->res_dev.cap_bits & CAP_LABEL) { - strcat(buf, "CAP_LABEL "); - } - if (res->res_dev.cap_bits & CAP_ANONVOLS) { - strcat(buf, "CAP_ANONVOLS "); - } - if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) { - strcat(buf, "CAP_ALWAYSOPEN "); - } - strcat(buf, "\n"); - sendit(sock, buf); - break; - case R_MSGS: - sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); - if (res->res_msgs.mail_cmd) - sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); - if (res->res_msgs.operator_cmd) - sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); - break; - default: - sendit(sock, _("Warning: unknown resource type %d\n"), type); - break; + case R_DIRECTOR: + sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name); + break; + case R_STORAGE: + sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n", + res->res_store.hdr.name, NPRT(res->res_store.SDaddr), + res->res_store.SDport, res->res_store.SDDport, + edit_utime(res->res_store.heartbeat_interval, buf)); + break; + case R_DEVICE: + sendit(sock, "Device: name=%s MediaType=%s Device=%s\n", + res->res_dev.hdr.name, + res->res_dev.media_type, res->res_dev.device_name); + sendit(sock, " rew_wait=%d min_bs=%d max_bs=%d\n", + res->res_dev.max_rewind_wait, res->res_dev.min_block_size, + res->res_dev.max_block_size); + sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n", + res->res_dev.max_volume_jobs, res->res_dev.max_volume_files, + res->res_dev.max_volume_size); + sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n", + res->res_dev.max_file_size, res->res_dev.volume_capacity); + strcpy(buf, " "); + if (res->res_dev.cap_bits & CAP_EOF) { + bstrncat(buf, "CAP_EOF ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_BSR) { + bstrncat(buf, "CAP_BSR ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_BSF) { + bstrncat(buf, "CAP_BSF ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_FSR) { + bstrncat(buf, "CAP_FSR ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_FSF) { + bstrncat(buf, "CAP_FSF ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_EOM) { + bstrncat(buf, "CAP_EOM ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_REM) { + bstrncat(buf, "CAP_REM ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_RACCESS) { + bstrncat(buf, "CAP_RACCESS ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_AUTOMOUNT) { + bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_LABEL) { + bstrncat(buf, "CAP_LABEL ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_ANONVOLS) { + bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf)); + } + if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) { + bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf)); + } + bstrncat(buf, "\n", sizeof(buf)); + sendit(sock, buf); + break; + case R_MSGS: + sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); + if (res->res_msgs.mail_cmd) + sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); + if (res->res_msgs.operator_cmd) + sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); + break; + default: + sendit(sock, _("Warning: unknown resource type %d\n"), type); + break; } if (recurse && res->res_dir.hdr.next) dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock); @@ -254,57 +254,57 @@ void free_resource(int type) switch (type) { case R_DIRECTOR: - if (res->res_dir.password) { - free(res->res_dir.password); - } - if (res->res_dir.address) { - free(res->res_dir.address); - } - break; + if (res->res_dir.password) { + free(res->res_dir.password); + } + if (res->res_dir.address) { + free(res->res_dir.address); + } + break; case R_STORAGE: - if (res->res_store.address) { /* ***FIXME*** deprecated */ - free(res->res_store.address); - } - if (res->res_store.SDaddr) { - free(res->res_store.SDaddr); - } - if (res->res_store.working_directory) { - free(res->res_store.working_directory); - } - if (res->res_store.pid_directory) { - free(res->res_store.pid_directory); - } - if (res->res_store.subsys_directory) { - free(res->res_store.subsys_directory); - } - break; + if (res->res_store.address) { /* ***FIXME*** deprecated */ + free(res->res_store.address); + } + if (res->res_store.SDaddr) { + free(res->res_store.SDaddr); + } + if (res->res_store.working_directory) { + free(res->res_store.working_directory); + } + if (res->res_store.pid_directory) { + free(res->res_store.pid_directory); + } + if (res->res_store.subsys_directory) { + free(res->res_store.subsys_directory); + } + break; case R_DEVICE: - if (res->res_dev.media_type) { - free(res->res_dev.media_type); - } - if (res->res_dev.device_name) { - free(res->res_dev.device_name); - } - if (res->res_dev.changer_name) { - free(res->res_dev.changer_name); - } - if (res->res_dev.changer_command) { - free(res->res_dev.changer_command); - } - break; + if (res->res_dev.media_type) { + free(res->res_dev.media_type); + } + if (res->res_dev.device_name) { + free(res->res_dev.device_name); + } + if (res->res_dev.changer_name) { + free(res->res_dev.changer_name); + } + if (res->res_dev.changer_command) { + free(res->res_dev.changer_command); + } + break; case R_MSGS: - if (res->res_msgs.mail_cmd) { - free(res->res_msgs.mail_cmd); - } - if (res->res_msgs.operator_cmd) { - free(res->res_msgs.operator_cmd); - } - free_msgs_res((MSGS *)res); /* free message resource */ - res = NULL; - break; + if (res->res_msgs.mail_cmd) { + free(res->res_msgs.mail_cmd); + } + if (res->res_msgs.operator_cmd) { + free(res->res_msgs.operator_cmd); + } + free_msgs_res((MSGS *)res); /* free message resource */ + res = NULL; + break; default: Dmsg1(0, "Unknown resource type %d\n", type); - break; + break; } /* Common stuff again -- free the resource, recurse to next one */ if (res) { @@ -332,10 +332,10 @@ void save_resource(int type, struct res_items *items, int pass) */ for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { - if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { + if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"), - items[i].name, resources[rindex]); - } + items[i].name, resources[rindex]); + } } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { @@ -350,33 +350,33 @@ void save_resource(int type, struct res_items *items, int pass) */ if (pass == 2) { switch (type) { - /* Resources not containing a resource */ - case R_DIRECTOR: - case R_DEVICE: - case R_MSGS: - break; - - /* Resources containing a resource */ - case R_STORAGE: - if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) { + /* Resources not containing a resource */ + case R_DIRECTOR: + case R_DEVICE: + case R_MSGS: + break; + + /* Resources containing a resource */ + case R_STORAGE: + if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) { Emsg1(M_ABORT, 0, "Cannot find Storage resource %s\n", res_all.res_dir.hdr.name); - } - res->res_store.messages = res_all.res_store.messages; - break; - default: + } + res->res_store.messages = res_all.res_store.messages; + break; + default: printf("Unknown resource type %d\n", type); - error = 1; - break; + error = 1; + break; } if (res_all.res_dir.hdr.name) { - free(res_all.res_dir.hdr.name); - res_all.res_dir.hdr.name = NULL; + free(res_all.res_dir.hdr.name); + res_all.res_dir.hdr.name = NULL; } if (res_all.res_dir.hdr.desc) { - free(res_all.res_dir.hdr.desc); - res_all.res_dir.hdr.desc = NULL; + free(res_all.res_dir.hdr.desc); + res_all.res_dir.hdr.desc = NULL; } return; } @@ -384,42 +384,42 @@ void save_resource(int type, struct res_items *items, int pass) /* The following code is only executed on pass 1 */ switch (type) { case R_DIRECTOR: - size = sizeof(DIRRES); - break; + size = sizeof(DIRRES); + break; case R_STORAGE: - size = sizeof(STORES); - break; + size = sizeof(STORES); + break; case R_DEVICE: - size = sizeof(DEVRES); - break; + size = sizeof(DEVRES); + break; case R_MSGS: - size = sizeof(MSGS); - break; + size = sizeof(MSGS); + break; default: printf("Unknown resource type %d\n", type); - error = 1; - size = 1; - break; + error = 1; + size = 1; + break; } /* Common */ if (!error) { res = (URES *)malloc(size); memcpy(res, &res_all, size); if (!resources[rindex].res_head) { - resources[rindex].res_head = (RES *)res; /* store first entry */ + resources[rindex].res_head = (RES *)res; /* store first entry */ } else { - RES *next; - /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) { - if (strcmp(next->name, res->res_dir.hdr.name) == 0) { - Emsg2(M_ERROR_TERM, 0, + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), - resources[rindex].name, res->res_dir.hdr.name); - } - } - next->next = (RES *)res; + resources[rindex].name, res->res_dir.hdr.name); + } + } + next->next = (RES *)res; Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), - res->res_dir.hdr.name); + res->res_dir.hdr.name); } } } diff --git a/bacula/src/version.h b/bacula/src/version.h index ecbe93e12c..0c6a81cfde 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.33" #define VSTRING "1" -#define BDATE "24 Nov 2003" -#define LSMDATE "24Nov03" +#define BDATE "28 Nov 2003" +#define LSMDATE "28Nov03" /* Debug flags */ #undef DEBUG