]> git.sur5r.net Git - bacula/bacula/commitdiff
Implement saving last 10 jobs run
authorKern Sibbald <kern@sibbald.com>
Fri, 28 Nov 2003 14:59:02 +0000 (14:59 +0000)
committerKern Sibbald <kern@sibbald.com>
Fri, 28 Nov 2003 14:59:02 +0000 (14:59 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@816 91ce42f0-d328-0410-95d8-f526ca767f89

17 files changed:
bacula/kernstodo
bacula/platforms/redhat/bacula.spec.in
bacula/src/dird/dird.c
bacula/src/dird/ua_restore.c
bacula/src/dird/ua_status.c
bacula/src/dird/ua_tree.c
bacula/src/filed/filed.c
bacula/src/filed/status.c
bacula/src/jcr.h
bacula/src/lib/jcr.c
bacula/src/lib/message.c
bacula/src/lib/protos.h
bacula/src/stored/acquire.c
bacula/src/stored/status.c
bacula/src/stored/stored.c
bacula/src/stored/stored_conf.c
bacula/src/version.h

index 596b22bb8c33090dc2dab60ddf7a958a10b6f20f..8aa46fd83c465d68215fb677583b382a5dee8516 100644 (file)
@@ -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:
+
index 6c604039d64308e45f80c1302c54b5e2d63e61e4..d8fba455fa0f8b02070fa804d931808fc2a85f97 100644 (file)
@@ -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 <barninger at fairfieldcomputers.com>
+- removed make_static_bacula script from rescue package install
 * Sun Nov 23 2003 D. Scott Barninger <barninger at fairfieldcomputers.com>
 - Added define at top of file for depkgs version
 - Added rescue sub-package
index 410cbb5d36c06e941f3cbb674f4561b702925533..b4130421222ccb25418d89b9b262928c47c2d9b4 100644 (file)
@@ -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) {
index 0fcdea61774fc9f6696a1afc95c00acb3d18a4ec..4657662a301ac0b18120e6e9cdc211922f0a542f 100644 (file)
@@ -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;
    }
index c9aaede5bae53817ee53d15b73217604974e3b90..36410af26146ad90dfa4f7c6f1d614db133fbd4d 100644 (file)
@@ -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();
+}
index d914868c53d2f16f60276d9f7075348609c20792..089eaee403d8a096150f90d708eba3daa23f0373 100644 (file)
@@ -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;
 }
index 1c321e7d7bab7181d98d6cf621485db91a2e8831..aa8dbe07bef51fda265f104efa9936502e179e22 100644 (file)
@@ -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 */
index c1c6ce18783737fa69b19fa0f49e089156ebd985..806a98d70c183ea9be2a15382ada5f1a592cbc83 100755 (executable)
@@ -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 <windows.h>
 
index 0d6a9818828c539ccc0c97cef2493ff5951dbcd2..8a47e2e6c36acbe29f2800004c8a2c1901a5c40b 100644 (file)
@@ -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 */
index ee884d16345cae809c59e92af571a616dc55d157..03c86d08b5cfda25569940ff435b596444bea5fd 100755 (executable)
 
 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");
index 5008b08788b634933a3e683e05de952d9380cdd2..6391df5908e564a30413d0e68cd1239bf83c1d54 100755 (executable)
@@ -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();
 }
 
 
index 6c06d15f514f46a8588e3f56133fdbc0548ff603..24bd211d243d13db2c4bed15537e1c42f62d656b 100644 (file)
@@ -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);
index ddeee967f9af01c47d112f877a033b16b5b610ff..6991f271b5fc97ef67cd50ea9bb5f8480193115a 100644 (file)
@@ -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);
index 0d135886982cfb98424be12cd4b28cd70180b79f..f1b775f6f457ad48f945edce5c6875cb0380cfbd 100644 (file)
@@ -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);
+}
index 96ba176f9707a6f276968a3222859480b8a70f96..a83e70bd015f9ba42108b5ee220cbedf7438f847 100644 (file)
@@ -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) {
index d9f2cfa40cfe496bb49797024d7d74d48e052b76..5d1eee1c018cccddfc07cbdd39471979255f8163 100644 (file)
@@ -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);
       }
    }
 }
index ecbe93e12ca00f6fcf00432c867760783430c077..0c6a81cfde087926ecdae19983ad0f3f52078af9 100644 (file)
@@ -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