]> git.sur5r.net Git - bacula/bacula/commitdiff
relabel command, first cut label barcodes
authorKern Sibbald <kern@sibbald.com>
Fri, 4 Apr 2003 20:18:26 +0000 (20:18 +0000)
committerKern Sibbald <kern@sibbald.com>
Fri, 4 Apr 2003 20:18:26 +0000 (20:18 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@419 91ce42f0-d328-0410-95d8-f526ca767f89

14 files changed:
bacula/ReleaseNotes
bacula/kernstodo
bacula/src/cats/sql_delete.c
bacula/src/dird/Makefile.in
bacula/src/dird/job.c
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_label.c [new file with mode: 0644]
bacula/src/dird/ua_select.c
bacula/src/jcr.h
bacula/src/stored/Makefile.in
bacula/src/stored/autochanger.c [new file with mode: 0644]
bacula/src/stored/dircmd.c
bacula/src/stored/mount.c
bacula/src/stored/protos.h

index eb5cfdefc470ef049bc98c16aabbcb395a06a292..b5e8ae3ddd696847e45453215f18de0a408f8ac0 100644 (file)
@@ -1,19 +1,20 @@
           Release Notes for Bacula 1.30
 
-  Bacula code: Total files = 231 Total lines = 65,064 (*.h *.c *.in)
+  Bacula code: Total files = 233 Total lines = 65,765 (*.h *.c *.in)
 
 Major Changes this Release:
-- The Windows Client now uses Cygwin 1.3.20 and should be much more reliable.                    
+- The Windows Client now uses Cygwin 1.3.20 and should be much 
+  more reliable.                    
 - Implemented save/restore of chflags for FreeBSD systems.
 - Support for FreeBSD tape drives.
 - Support for SHA1 signatures in addition to MD5 (more secure).
+- The btape "test" command is much more comprehensive and automatically
+  tries different options.
 
 Other Changes this Release:
 - Added "BSF at EOM = yes/no" for supporting FreeBSD tape drives.
 - The | and < options are now available for Excludes.           
 - Multiple Directors in the GNOME Console now work (thanks Lutz Kttler).
-- The btape "test" command is much more comprehensive and automatically
-  tries different options.
 - Installation on Cygwin systems is now supported.
 - GNOME Console has font support thanks to Phil Stracchino.
 - Solaris 2.6 now supported.
@@ -23,7 +24,10 @@ Other Changes this Release:
 - Partial support for AIX systems.
 - Cycle through tapes with "RecycleOldestVolume=yes" (dangerous).
 - Support for Win95 systems (I hope).
-- Console program now supported on Win32 systems.
+- Console program now supported on Win32 systems as well as 
+  several other utility programs.
+- Full listing of most catalog records (llist command).
+- Relabel Purged tapes with the relabel command.
 
 
 Items to note:
index 1125308619fed2fb2ba6b0a7f32074fb03a9a987..4dca20a714e1e7cc4bd797b276f3dbf032df4ef8 100644 (file)
@@ -20,14 +20,12 @@ Testing to do: (painful)
 - multiple simultaneous Volumes
 
 For 1.30 release:
-- Pool requested twice in "relabel" command.
-  Must delete old volume from catalog.
-- Make non-zero status from RunJobBefore/After error the job.
+- Add IP address to authentication failures. Implement M_SECURITY
+  message class.
 - Remove kern and kelvin from mysql_grant...
 - Install grant_mysql...
 - Look at Python for a Bacula scripting language -- www.python.org
 - add #define ENABLE_NLS for Gnome compile on SuSE.
-- Need define of int_least16_t in sha1.h for SuSE.
 - Figure out how to use ssh to protect Bacula communications.
 - Fix "access not allowed" for backup of files on WinXP.
 - Issue message to mount a new tape before the rewind.
@@ -914,3 +912,5 @@ rufus-dir: Volume used once. Marking Volume "File0003" as Used.
   that no longer exist on the machine -- so that we maintain
   say backups for 30 days, but if the file is deleted, we maintain
   the last copy for 1 year.  -- answer Volume retention.
+- Make non-zero status from RunJobBefore/After error the job.
+- Need define of int_least16_t in sha1.h for SuSE.
index 244b0b3411cbefed5ffdb775805a934810199554..e5961e9ab23668a7af2c045d6f22cc947d5aeb65 100644 (file)
@@ -190,14 +190,20 @@ static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
  */
 int db_delete_media_record(void *jcr, B_DB *mdb, MEDIA_DBR *mr)
 {
+   db_lock(mdb);
    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
+      db_unlock(mdb);
       return 0;
    } 
-   /* Delete associated records */
-   do_media_purge(mdb, mr);
+   /* Do purge if not already purged */
+   if (strcmp(mr->VolStatus, "Purged") != 0) {
+      /* Delete associated records */
+      do_media_purge(mdb, mr);
+   }
 
    Mmsg(&mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
    db_sql_query(mdb, mdb->cmd, NULL, (void *)NULL);
+   db_unlock(mdb);
    return 1;
 }
 
@@ -209,18 +215,22 @@ int db_delete_media_record(void *jcr, B_DB *mdb, MEDIA_DBR *mr)
  */
 int db_purge_media_record(void *jcr, B_DB *mdb, MEDIA_DBR *mr)
 {
+   db_lock(mdb);
    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
+      db_unlock(mdb);
       return 0;
    } 
    /* Delete associated records */
-   do_media_purge(mdb, mr);
+   do_media_purge(mdb, mr);          /* Note, always purge */
 
    /* Mark Volume as purged */
    strcpy(mr->VolStatus, "Purged");
    if (!db_update_media_record(jcr, mdb, mr)) {
+      db_unlock(mdb);
       return 0;
    }
 
+   db_unlock(mdb);
    return 1;
 }
 
index 3eebd8b51bc75134eb7e083eec0f2e9d34c9916a..5ec19ed3e2d8eee238953ba03e578a900bade141 100644 (file)
@@ -31,7 +31,7 @@ SVRSRCS = dird.c authenticate.c autoprune.c \
          scheduler.c sql_cmds.c \
          ua_cmds.c ua_dotcmds.c \
          ua_db_query.c ua_retention.c \
-         ua_input.c ua_output.c ua_prune.c \
+         ua_input.c ua_label.c ua_output.c ua_prune.c \
          ua_purge.c ua_restore.c ua_run.c \
          ua_select.c ua_server.c \
          ua_status.c verify.c
@@ -44,7 +44,7 @@ SVROBJS = dird.o authenticate.o autoprune.o \
          scheduler.o sql_cmds.o \
          ua_cmds.o ua_dotcmds.o \
          ua_db_query.o ua_retention.o \
-         ua_input.o ua_output.o ua_prune.o \
+         ua_input.o ua_label.o ua_output.o ua_prune.o \
          ua_purge.o ua_restore.o ua_run.o \
          ua_select.o ua_server.o \
          ua_status.o verify.o
index 451e6502589c8d5d0caf316b316af40e4b166105..77fecf011526be4d4d69316cac4324cda8f6cca3 100644 (file)
@@ -176,18 +176,18 @@ static void *job_thread(void *arg)
    sm_check(__FILE__, __LINE__, True);
 
    if (!acquire_resource_locks(jcr)) {
-      set_jcr_job_status(jcr, JS_Cancelled);
+      set_jcr_job_status(jcr, JS_Canceled);
    }
 
    Dmsg0(200, "=====Start Job=========\n");
    jcr->start_time = time(NULL);      /* set the real start time */
-   Dmsg2(200, "jcr->JobStatus=%d %c\n", jcr->JobStatus, (char)jcr->JobStatus);
-   if (job_cancelled(jcr)) {
+
+   if (job_canceled(jcr)) {
       update_job_end_record(jcr);
    } else if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
        (utime_t)(jcr->start_time - jcr->sched_time)) {
-      Jmsg(jcr, M_FATAL, 0, _("Job cancelled because max start delay time exceeded.\n"));
-      set_jcr_job_status(jcr, JS_Cancelled);
+      Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
+      set_jcr_job_status(jcr, JS_Canceled);
       update_job_end_record(jcr);
    } else {
 
@@ -200,6 +200,14 @@ static void *job_thread(void *arg)
         
         before = edit_run_codes(jcr, before, jcr->job->RunBeforeJob);
         status = run_program(before, 0, NULL);
+        if (status != 0) {
+            Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob returned non-zero status=%d\n"),
+              status);
+           set_jcr_job_status(jcr, JS_FatalError);
+           update_job_end_record(jcr);
+           free_pool_memory(before);
+           goto bail_out;
+        }
         free_pool_memory(before);
       }
       switch (jcr->JobType) {
@@ -236,9 +244,16 @@ static void *job_thread(void *arg)
       
         after = edit_run_codes(jcr, after, jcr->job->RunAfterJob);
         status = run_program(after, 0, NULL);
+        if (status != 0) {
+            Jmsg(jcr, M_FATAL, 0, _("RunAfterJob returned non-zero status=%d\n"),
+              status);
+           set_jcr_job_status(jcr, JS_FatalError);
+           update_job_end_record(jcr);
+        }
         free_pool_memory(after);
       }
    }
+bail_out:
    release_resource_locks(jcr);
    Dmsg0(50, "Before free jcr\n");
    free_jcr(jcr);
index 0b81d81bd9afb4c124dabc401d6772c21fbea117..ca6b080872eda923315e5cf8ad0a0ceb0a551633 100644 (file)
@@ -58,6 +58,8 @@ extern int retentioncmd(UAContext *ua, char *cmd);
 extern int prunecmd(UAContext *ua, char *cmd);
 extern int purgecmd(UAContext *ua, char *cmd);
 extern int restorecmd(UAContext *ua, char *cmd);
+extern int labelcmd(UAContext *ua, char *cmd);
+extern int relabelcmd(UAContext *ua, char *cmd);
 
 /* Forward referenced functions */
 static int addcmd(UAContext *ua, char *cmd),  createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd);
@@ -65,15 +67,14 @@ static int setdebugcmd(UAContext *ua, char *cmd);
 static int helpcmd(UAContext *ua, char *cmd);
 static int deletecmd(UAContext *ua, char *cmd);
 static int usecmd(UAContext *ua, char *cmd),  unmountcmd(UAContext *ua, char *cmd);
-static int labelcmd(UAContext *ua, char *cmd), mountcmd(UAContext *ua, char *cmd), updatecmd(UAContext *ua, char *cmd);
-static int relabelcmd(UAContext *ua, char *cmd), mountcmd(UAContext *ua, char *cmd), updatecmd(UAContext *ua, char *cmd);
 static int versioncmd(UAContext *ua, char *cmd), automountcmd(UAContext *ua, char *cmd);
 static int timecmd(UAContext *ua, char *cmd);
 static int update_volume(UAContext *ua);
 static int update_pool(UAContext *ua);
 static int delete_volume(UAContext *ua);
 static int delete_pool(UAContext *ua);
-static int do_label(UAContext *ua, char *cmd, int relabel);
+static int mountcmd(UAContext *ua, char *cmd);
+static int updatecmd(UAContext *ua, char *cmd);
 
 int quitcmd(UAContext *ua, char *cmd);
 
@@ -1110,7 +1111,7 @@ static int setdebugcmd(UAContext *ua, char *cmd)
       if (strcasecmp(ua->argk[i], _("client")) == 0) {
         client = NULL;
         if (ua->argv[i]) {
-           client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
+           client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
            if (client) {
               do_client_setdebug(ua, client, level);
               return 1;
@@ -1121,7 +1122,18 @@ static int setdebugcmd(UAContext *ua, char *cmd)
            do_client_setdebug(ua, client, level);
            return 1;
         }
+      }
 
+      if (strcasecmp(ua->argk[i], _("store")) == 0 ||
+          strcasecmp(ua->argk[i], _("storage")) == 0) {
+        store = NULL;
+        if (ua->argv[i]) {
+           store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
+           if (store) {
+              do_storage_setdebug(ua, store, level);
+              return 1;
+           }
+        }
         store = get_storage_resource(ua, cmd);
         if (store) {
            do_storage_setdebug(ua, store, level);
@@ -1270,199 +1282,6 @@ static int delete_pool(UAContext *ua)
 }
 
 
-/*
- * Label a tape 
- *  
- *   label storage=xxx volume=vvv
- */
-static int labelcmd(UAContext *ua, char *cmd)
-{
-   return do_label(ua, cmd, 0);       /* standard label */
-}
-
-static int relabelcmd(UAContext *ua, char *cmd)
-{
-   return do_label(ua, cmd, 1);      /* relabel tape */
-}
-
-
-/*
- * Common routine for both label and relabel
- */
-static int do_label(UAContext *ua, char *cmd, int relabel)
-{
-   STORE *store;
-   BSOCK *sd;
-   char dev_name[MAX_NAME_LENGTH];
-   MEDIA_DBR mr, omr;
-   POOL_DBR pr;
-   int ok = FALSE;
-   int mounted = FALSE;
-   int i;
-   int slot = 0;
-   static char *name_keyword[] = {
-      "name",
-      NULL};
-
-   static char *vol_keyword[] = {
-      "volume",
-      NULL};
-
-
-   if (!open_db(ua)) {
-      return 1;
-   }
-   store = get_storage_resource(ua, cmd);
-   if (!store) {
-      return 1;
-   }
-
-   /* If relabel get name of Volume to relabel */
-   if (relabel) {
-      i = find_arg_keyword(ua, vol_keyword); 
-      if (i >= 0 && ua->argv[i]) {
-        memset(&omr, 0, sizeof(omr));
-        bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
-        if (!db_get_media_record(ua->jcr, ua->db, &omr)) {
-            bsendmsg(ua, "%s", db_strerror(ua->db));
-           goto getVol;
-        }
-        goto gotVol;
-      }
-getVol:
-      if (!select_pool_and_media_dbr(ua, &pr, &omr)) {
-        return 1;
-      }
-
-gotVol:
-      if (strcmp(omr.VolStatus, "Purged") != 0) {
-         bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"),
-           omr.VolumeName, omr.VolStatus);
-        return 1;
-      }
-   }
-
-   i = find_arg_keyword(ua, name_keyword);
-   if (i >=0 && ua->argv[i]) {
-      strcpy(ua->cmd, ua->argv[i]);
-      goto gotName;
-   }
-
-getName:
-   if (!get_cmd(ua, _("Enter new Volume name: "))) {
-      return 1;
-   }
-gotName:
-   /* ****FIXME*** be much more restrictive in the name */
-   if (strpbrk(ua->cmd, "`~!@#$%^&*()[]{}|\\;'\"<>?,/")) {
-      bsendmsg(ua, _("Illegal character | in a volume name.\n"));
-      goto getName;
-   }
-   if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
-      bsendmsg(ua, _("Volume name too long.\n"));
-      goto getVol;
-   }
-   if (strlen(ua->cmd) == 0) {
-      bsendmsg(ua, _("Volume name must be at least one character long.\n"));
-      goto getName;
-   }
-
-   memset(&mr, 0, sizeof(mr));
-   strcpy(mr.VolumeName, ua->cmd);
-   if (db_get_media_record(ua->jcr, ua->db, &mr)) {
-       bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
-         mr.VolumeName);
-       goto getName;
-   }
-
-   /* Do some more checking on slot ****FIXME**** */
-   if (store->autochanger) {
-      if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
-        return 1;
-      }
-      slot = atoi(ua->cmd);
-   }
-   strcpy(mr.MediaType, store->media_type);
-   mr.Slot = slot;
-
-   memset(&pr, 0, sizeof(pr));
-   if (!select_pool_dbr(ua, &pr)) {
-      return 1;
-   }
-
-   ua->jcr->store = store;
-   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
-      store->hdr.name, store->address, store->SDport);
-   if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
-      bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
-      return 1;   
-   }
-   sd = ua->jcr->store_bsock;
-   strcpy(dev_name, store->dev_name);
-   bash_spaces(dev_name);
-   bash_spaces(mr.VolumeName);
-   bash_spaces(mr.MediaType);
-   bash_spaces(pr.Name);
-   if (relabel) {
-      bash_spaces(omr.VolumeName);
-      bnet_fsend(sd, _("relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d"), 
-        dev_name, omr.VolumeName, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
-      bsendmsg(ua, _("Sending relabel command ...\n"));
-   } else {
-      bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), 
-        dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
-      bsendmsg(ua, _("Sending label command ...\n"));
-   }
-   while (bget_msg(sd, 0) >= 0) {
-      bsendmsg(ua, "%s", sd->msg);
-      if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
-        ok = TRUE;
-      } else {
-         bsendmsg(ua, _("Label command failed.\n"));
-      }
-   }
-   ua->jcr->store_bsock = NULL;
-   unbash_spaces(dev_name);
-   unbash_spaces(mr.VolumeName);
-   unbash_spaces(mr.MediaType);
-   unbash_spaces(pr.Name);
-   mr.LabelDate = time(NULL);
-   if (ok) {
-      set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
-      if (db_create_media_record(ua->jcr, ua->db, &mr)) {
-         bsendmsg(ua, _("Media record for Volume \"%s\" successfully created.\n"),
-           mr.VolumeName);
-        if (ua->automount) {
-            bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
-           bash_spaces(dev_name);
-            bnet_fsend(sd, "mount %s", dev_name);
-           unbash_spaces(dev_name);
-           while (bnet_recv(sd) >= 0) {
-               bsendmsg(ua, "%s", sd->msg);
-              /* Here we can get
-               *  3001 OK mount. Device=xxx      or
-               *  3001 Mounted Volume vvvv
-               */
-               if (strncmp(sd->msg, "3001 ", 5) == 0) {
-                 mounted = TRUE;
-                 /***** ****FIXME***** find job waiting for  
-                  ***** mount, and change to waiting for SD  
-                  */
-              }
-           }
-        }
-      } else {
-         bsendmsg(ua, "%s", db_strerror(ua->db));
-      }
-   }
-   if (!mounted) {
-      bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
-   }
-   bnet_sig(sd, BNET_TERMINATE);
-   bnet_close(sd);
-   return 1;
-}
-
 static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
 {
    STORE *store;
diff --git a/bacula/src/dird/ua_label.c b/bacula/src/dird/ua_label.c
new file mode 100644 (file)
index 0000000..871d141
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ *
+ *   Bacula Director -- Tape labeling commands
+ *
+ *     Kern Sibbald, April MMIII
+ *
+ *   Version $Id$
+ */
+
+/*
+   Copyright (C) 2000-2003 Kern Sibbald and John Walker
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public
+   License along with this program; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+ */
+
+#include "bacula.h"
+#include "dird.h"
+
+/* Imported subroutines */
+
+/* Imported variables */
+
+
+/* Imported functions */
+
+/* Forward referenced functions */
+static int do_label(UAContext *ua, char *cmd, int relabel);
+static void label_from_barcodes(UAContext *ua);
+
+/*
+ * Label a tape 
+ *  
+ *   label storage=xxx volume=vvv
+ */
+int labelcmd(UAContext *ua, char *cmd)
+{
+   return do_label(ua, cmd, 0);       /* standard label */
+}
+
+int relabelcmd(UAContext *ua, char *cmd)
+{
+   return do_label(ua, cmd, 1);      /* relabel tape */
+}
+
+
+/*
+ * Common routine for both label and relabel
+ */
+static int do_label(UAContext *ua, char *cmd, int relabel)
+{
+   STORE *store;
+   BSOCK *sd;
+   char dev_name[MAX_NAME_LENGTH];
+   MEDIA_DBR mr, omr;
+   POOL_DBR pr;
+   int ok = FALSE;
+   int mounted = FALSE;
+   int i;
+   int slot = 0;
+   static char *name_keyword[] = {
+      "name",
+      NULL};
+   static char *vol_keyword[] = {
+      "volume",
+      NULL};
+   static char *barcode_keyword[] = {
+      "barcode",
+      "barcodes",
+      NULL};
+
+
+   memset(&pr, 0, sizeof(pr));
+   if (!open_db(ua)) {
+      return 1;
+   }
+   store = get_storage_resource(ua, cmd);
+   if (!store) {
+      return 1;
+   }
+   ua->jcr->store = store;
+
+   if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
+      label_from_barcodes(ua);
+      return 1;
+   }
+
+   /* If relabel get name of Volume to relabel */
+   if (relabel) {
+      /* Check for volume=OldVolume */
+      i = find_arg_keyword(ua, vol_keyword); 
+      if (i >= 0 && ua->argv[i]) {
+        memset(&omr, 0, sizeof(omr));
+        bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
+        if (db_get_media_record(ua->jcr, ua->db, &omr)) {
+           goto checkVol;
+        } 
+         bsendmsg(ua, "%s", db_strerror(ua->db));
+      }
+      /* No keyword or Vol not found, ask user to select */
+      if (!select_pool_and_media_dbr(ua, &pr, &omr)) {
+        return 1;
+      }
+
+      /* Require Volume to be Purged */
+checkVol:
+      if (strcmp(omr.VolStatus, "Purged") != 0) {
+         bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"),
+           omr.VolumeName, omr.VolStatus);
+        return 1;
+      }
+   }
+
+   /* Check for name=NewVolume */
+   i = find_arg_keyword(ua, name_keyword);
+   if (i >=0 && ua->argv[i]) {
+      strcpy(ua->cmd, ua->argv[i]);
+      goto checkName;
+   }
+
+   /* Get a new Volume name */
+   for ( ;; ) {
+      if (!get_cmd(ua, _("Enter new Volume name: "))) {
+        return 1;
+      }
+checkName:
+      /* Restrict the characters permitted in the Volume name */
+      if (strpbrk(ua->cmd, "`~!@#$%^&*()[]{}|\\;'\"<>?,/")) {
+         bsendmsg(ua, _("Illegal character | in a volume name.\n"));
+        continue;
+      }
+      if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
+         bsendmsg(ua, _("Volume name too long.\n"));
+        continue;
+      }
+      if (strlen(ua->cmd) == 0) {
+         bsendmsg(ua, _("Volume name must be at least one character long.\n"));
+        continue;
+      }
+
+      memset(&mr, 0, sizeof(mr));
+      strcpy(mr.VolumeName, ua->cmd);
+      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
+          bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
+            mr.VolumeName);
+         continue;
+      }
+      break;                         /* Got it */
+   }
+
+   /* Do some more checking on slot ****FIXME**** */
+   if (store->autochanger) {
+      for ( ;; ) {
+         if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
+           return 1;
+        }
+        slot = atoi(ua->cmd);
+        if (slot >= 0) {             /* OK */
+           break;
+        }
+         bsendmsg(ua, _("Slot numbers must be positive.\n"));
+      }
+   }
+   strcpy(mr.MediaType, store->media_type);
+   mr.Slot = slot;
+
+   /* Must select Pool if not already done */
+   if (pr.PoolId == 0) {
+      memset(&pr, 0, sizeof(pr));
+      if (!select_pool_dbr(ua, &pr)) {
+        return 1;
+      }
+   }
+
+   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
+      store->hdr.name, store->address, store->SDport);
+   if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+      bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+      return 1;   
+   }
+   sd = ua->jcr->store_bsock;
+   strcpy(dev_name, store->dev_name);
+   bash_spaces(dev_name);
+   bash_spaces(mr.VolumeName);
+   bash_spaces(mr.MediaType);
+   bash_spaces(pr.Name);
+   if (relabel) {
+      bash_spaces(omr.VolumeName);
+      bnet_fsend(sd, _("relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d"), 
+        dev_name, omr.VolumeName, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
+      bsendmsg(ua, _("Sending relabel command ...\n"));
+   } else {
+      bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), 
+        dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
+      bsendmsg(ua, _("Sending label command ...\n"));
+   }
+   while (bget_msg(sd, 0) >= 0) {
+      bsendmsg(ua, "%s", sd->msg);
+      if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
+        ok = TRUE;
+      } else {
+         bsendmsg(ua, _("Label command failed.\n"));
+      }
+   }
+   ua->jcr->store_bsock = NULL;
+   unbash_spaces(dev_name);
+   unbash_spaces(mr.VolumeName);
+   unbash_spaces(mr.MediaType);
+   unbash_spaces(pr.Name);
+   mr.LabelDate = time(NULL);
+   if (ok) {
+      set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
+      if (db_create_media_record(ua->jcr, ua->db, &mr)) {
+         bsendmsg(ua, _("Media record for Volume \"%s\" successfully created.\n"),
+           mr.VolumeName);
+        if (ua->automount) {
+            bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
+           bash_spaces(dev_name);
+            bnet_fsend(sd, "mount %s", dev_name);
+           unbash_spaces(dev_name);
+           while (bnet_recv(sd) >= 0) {
+               bsendmsg(ua, "%s", sd->msg);
+              /* Here we can get
+               *  3001 OK mount. Device=xxx      or
+               *  3001 Mounted Volume vvvv
+               */
+               if (strncmp(sd->msg, "3001 ", 5) == 0) {
+                 mounted = TRUE;
+                 /***** ****FIXME***** find job waiting for  
+                  ***** mount, and change to waiting for SD  
+                  */
+              }
+           }
+        }
+      } else {
+         bsendmsg(ua, "%s", db_strerror(ua->db));
+      }
+      if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
+         bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
+           omr.VolumeName, db_strerror(ua->db));
+      } else {
+         bsendmsg(ua, _("Volume \"%s\" deleted from catalog.\n"));
+      }
+   }
+   if (!mounted) {
+      bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
+   }
+   bnet_sig(sd, BNET_TERMINATE);
+   bnet_close(sd);
+   ua->jcr->store_bsock = NULL;
+
+   return 1;
+}
+
+static void label_from_barcodes(UAContext *ua)
+{
+   STORE *store = ua->jcr->store;
+   BSOCK *sd;
+   POOL_DBR pr;
+   char dev_name[MAX_NAME_LENGTH];
+
+   bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
+      store->hdr.name, store->address, store->SDport);
+   if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+      bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
+      return;
+   }
+
+   strcpy(dev_name, store->dev_name);
+   bash_spaces(dev_name);
+   sd = ua->jcr->store_bsock;
+   bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
+   while (bget_msg(sd, 0) >= 0) {
+      bsendmsg(ua, "%s", sd->msg);
+   }
+   bnet_sig(sd, BNET_TERMINATE);
+   bnet_close(sd);
+   ua->jcr->store_bsock = NULL;
+
+   memset(&pr, 0, sizeof(pr));
+   if (!select_pool_dbr(ua, &pr)) {
+      return;
+   }
+
+   return;
+}
index 824602a6e8649d08021c4ef7e8ec7ef2399fc277..c6ccc313a258837a463f7909ab418d6bd8bc8c37 100644 (file)
@@ -660,7 +660,6 @@ int do_prompt(UAContext *ua, char *msg, char *prompt, int max_prompt)
 
 /*
  * We scan what the user has entered looking for
- *    <storage-resource>
  *    device=<device-name>     ???? does this work ????
  *    storage=<storage-resource>
  *    job=<job_name>
@@ -676,10 +675,6 @@ STORE *get_storage_resource(UAContext *ua, char *cmd)
    JCR *jcr;
    int i;
       
-   if (ua->argc == 1) {
-      return select_storage_resource(ua);
-   }
-   
    device_name = NULL;
    store_name = NULL;
 
index c96dabbd1cabe7eb65b945a041850c050bb923e8..5df133ccdc8ff20eeeb30ee9f477b1f2553f04d9 100644 (file)
@@ -61,6 +61,7 @@
 #define JS_FatalError            'f'  /* Fatal error */
 #define JS_Differences           'D'  /* Verify differences */
 #define JS_Cancelled             'A'  /* cancelled by user */
+#define JS_Canceled              'A'  /* canceled by user */
 #define JS_WaitFD                'F'  /* waiting on File daemon */
 #define JS_WaitSD                'S'  /* waiting on the Storage daemon */
 #define JS_WaitMedia             'm'  /* waiting for new media */
 #define JS_WaitMaxJobs           'd'  /* Waiting for maximum jobs */
 
 #define job_cancelled(jcr) \
-  (jcr->JobStatus == JS_Cancelled || \
+  (jcr->JobStatus == JS_Canceled || \
    jcr->JobStatus == JS_ErrorTerminated || \
    jcr->JobStatus == JS_FatalError)
 
+#define job_canceled(jcr) \
+  (jcr->JobStatus == JS_Canceled || \
+   jcr->JobStatus == JS_ErrorTerminated || \
+   jcr->JobStatus == JS_FatalError)
+
+
 typedef void (JCR_free_HANDLER)(struct s_jcr *jcr);
 
 /* Job Control Record (JCR) */
index 8cbc821fba7bddc368ca6681705aefc1290e4ecd..9d4a53a02c2e4d0c8aac111a097aeb04c7b76f51 100644 (file)
@@ -18,12 +18,14 @@ first_rule: all
 dummy:
 
 # bacula-sd
-SVRSRCS = stored.c acquire.c append.c askdir.c authenticate.c \
+SVRSRCS = stored.c autochanger.c acquire.c append.c \
+         askdir.c authenticate.c \
          block.c dev.c \
          device.c dircmd.c fd_cmds.c fdmsg.c job.c \
          label.c match_bsr.c parse_bsr.c \
          read.c record.c stored_conf.c mount.c
-SVROBJS = stored.o acquire.o append.o askdir.o authenticate.o \
+SVROBJS = stored.o autochanger.o acquire.o append.o \
+         askdir.o authenticate.o \
          block.o dev.o \
          device.o dircmd.o fd_cmds.o fdmsg.o job.o \
          label.o match_bsr.o mount.o parse_bsr.o \
@@ -34,27 +36,27 @@ TAPESRCS = btape.c block.c butil.c dev.c device.c label.c \
           acquire.c mount.c record.c read_record.c \
           stored_conf.c match_bsr.c parse_bsr.o
 TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \
-          acquire.o mount.o record.o read_record.o \
+          autochanger.o acquire.o mount.o record.o read_record.o \
           stored_conf.o match_bsr.o parse_bsr.o
 
 # bls
 BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o \
-         acquire.o mount.o parse_bsr.o record.o  \
+         autochanger.o acquire.o mount.o parse_bsr.o record.o  \
          read_record.o stored_conf.o
 
 # bextract
 BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \
-          acquire.o mount.o match_bsr.o parse_bsr.o butil.o \
+          autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \
           read_record.o stored_conf.o
 
 # bscan
 SCNOBJS = bscan.o block.o device.o dev.o label.o \
-         acquire.o mount.o record.o match_bsr.o parse_bsr.o \
+         autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
          butil.o read_record.o stored_conf.o
 
 # bcopy
 COPYOBJS = bcopy.o block.o device.o dev.o label.o \
-          acquire.o mount.o record.o match_bsr.o parse_bsr.o \
+          autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
           butil.o read_record.o stored_conf.o
 
 
diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c
new file mode 100644 (file)
index 0000000..76d1e00
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *
+ *  Routines for handling the autochanger.
+ *
+ *   Kern Sibbald, August MMII
+ *                           
+ *   Version $Id$
+ */
+/*
+   Copyright (C) 2000-2003 Kern Sibbald and John Walker
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public
+   License along with this program; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+ */
+
+#include "bacula.h"                   /* pull in global headers */
+#include "stored.h"                   /* pull in Storage Deamon headers */
+
+/* Forward referenced functions */
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd);
+
+
+/*
+ * Called here to do an autoload using the autochanger, if
+ *  configured, and if a Slot has been defined for this Volume.
+ *  On success this routine loads the indicated tape, but the
+ *  label is not read, so it must be verified.
+ *
+ *  Note if dir is not NULL, it is the console requesting the 
+ *   autoload for labeling, so we respond directly to the
+ *   dir bsock.
+ *
+ *  Returns: 1 on success
+ *          0 on failure
+ */
+int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir)
+{
+   int slot = jcr->VolCatInfo.Slot;
+   int rtn_stat = 0;
+     
+   /*
+    * Handle autoloaders here. If we cannot autoload it, we
+    *  will return FALSE to ask the sysop.
+    */
+   if (writing && dev_cap(dev, CAP_AUTOCHANGER) && slot <= 0) {
+      if (dir) {
+        return 0;                    /* For user, bail out right now */
+      }
+      if (dir_find_next_appendable_volume(jcr)) {
+        slot = jcr->VolCatInfo.Slot; 
+      }
+   }
+   Dmsg1(100, "Want changer slot=%d\n", slot);
+
+   if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) {
+      uint32_t timeout = jcr->device->max_changer_wait;
+      POOLMEM *changer, *results;
+      int status, loaded;
+
+      results = get_pool_memory(PM_MESSAGE);
+      changer = get_pool_memory(PM_FNAME);
+
+      /* Find out what is loaded, zero means device is unloaded */
+      changer = edit_device_codes(jcr, changer, jcr->device->changer_command, 
+                   "loaded");
+      status = run_program(changer, timeout, results);
+      Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results);
+      if (status == 0) {
+        loaded = atoi(results);
+      } else {
+        loaded = -1;              /* force unload */
+      }
+      Dmsg1(100, "loaded=%s\n", results);
+
+      /* If bad status or tape we want is not loaded, load it. */
+      if (status != 0 || loaded != slot) { 
+        if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
+           offline_dev(dev);
+        }
+        /* We are going to load a new tape, so close the device */
+        force_close_dev(dev);
+        if (loaded != 0) {        /* must unload drive */
+            Dmsg0(100, "Doing changer unload.\n");
+           if (dir) {
+               bnet_fsend(dir, _("3902 Issuing autochanger \"unload\" command.\n"));
+           } else {
+               Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"unload\" command.\n"));
+           }
+           changer = edit_device_codes(jcr, changer, 
+                        jcr->device->changer_command, "unload");
+           status = run_program(changer, timeout, NULL);
+            Dmsg1(100, "unload status=%d\n", status);
+        }
+        /*
+         * Load the desired cassette    
+         */
+         Dmsg1(100, "Doing changer load slot %d\n", slot);
+        if (dir) {
+            bnet_fsend(dir, _("3903 Issuing autochanger \"load slot %d\" command.\n"),
+              slot);
+        } else {
+            Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"load slot %d\" command.\n"),
+              slot);
+        }
+        changer = edit_device_codes(jcr, changer, 
+                      jcr->device->changer_command, "load");
+        status = run_program(changer, timeout, NULL);
+        if (status == 0) {
+            Jmsg(jcr, M_INFO, 0, _("Autochanger \"load slot\" status is OK.\n"));
+        } else {
+            Jmsg(jcr, M_INFO, 0, _("Bad autochanger \"load slot\" status = %d.\n"),
+              status);
+        }
+         Dmsg2(100, "load slot %d status=%d\n", slot, status);
+      }
+      free_pool_memory(changer);
+      free_pool_memory(results);
+      Dmsg1(100, "After changer, status=%d\n", status);
+      if (status == 0) {          /* did we succeed? */
+        rtn_stat = 1;             /* tape loaded by changer */
+      }
+   }
+   return rtn_stat;
+}
+
+int autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir)
+{
+   uint32_t timeout = jcr->device->max_changer_wait;
+   POOLMEM *changer;
+   BPIPE *bpipe;
+   int len = sizeof_pool_memory(dir->msg) - 1;
+
+   if (!dev_cap(dev, CAP_AUTOCHANGER) || !jcr->device->changer_name ||
+       !jcr->device->changer_command) {
+      bnet_fsend(dir, _("Not a changer device.\n"));
+      return 0;
+   }
+
+   changer = get_pool_memory(PM_FNAME);
+   if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
+      offline_dev(dev);
+   }
+   /* We are going to load a new tape, so close the device */
+   force_close_dev(dev);
+
+   /* First unload any tape */
+   bnet_fsend(dir, _("3902 Issuing autochanger \"unload\" command.\n"));
+   changer = edit_device_codes(jcr, changer, jcr->device->changer_command, "unload");
+   run_program(changer, timeout, NULL);
+
+   /* Now list slots occupied */
+   changer = edit_device_codes(jcr, changer, jcr->device->changer_command, "list");
+   bnet_fsend(dir, _("3903 Issuing autochanger \"list\" command.\n"));
+   bpipe = open_bpipe(changer, timeout, "r");
+   if (!bpipe) {
+      bnet_fsend(dir, _("Open bpipe failed.\n"));
+      goto bail_out;
+   }
+   /* Get output from changer */
+   while (fgets(dir->msg, len, bpipe->rfd)) { 
+      dir->msglen = strlen(dir->msg);
+      bnet_send(dir);
+   }
+   bnet_sig(dir, BNET_EOD);
+   close_bpipe(bpipe);
+
+bail_out:
+   free_pool_memory(changer);
+   return 1;
+}
+
+
+
+/*
+ * Edit codes into ChangerCommand
+ *  %% = %
+ *  %a = archive device name
+ *  %c = changer device name
+ *  %f = Client's name
+ *  %j = Job name
+ *  %o = command
+ *  %s = Slot base 0
+ *  %S = Slot base 1
+ *  %v = Volume name
+ *
+ *
+ *  omsg = edited output message
+ *  imsg = input string containing edit codes (%x)
+ *  cmd = command string (load, unload, ...) 
+ *
+ */
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) 
+{
+   char *p;
+   const char *str;
+   char add[20];
+
+   *omsg = 0;
+   Dmsg1(200, "edit_device_codes: %s\n", imsg);
+   for (p=imsg; *p; p++) {
+      if (*p == '%') {
+        switch (*++p) {
+         case '%':
+            str = "%";
+           break;
+         case 'a':
+           str = jcr->device->dev->dev_name;
+           break;
+         case 'c':
+           str = NPRT(jcr->device->changer_name);
+           break;
+         case 'o':
+           str = NPRT(cmd);
+           break;
+         case 's':
+            sprintf(add, "%d", jcr->VolCatInfo.Slot - 1);
+           str = add;
+           break;
+         case 'S':
+            sprintf(add, "%d", jcr->VolCatInfo.Slot);
+           str = add;
+           break;
+         case 'j':                    /* Job name */
+           str = jcr->Job;
+           break;
+         case 'v':
+           str = NPRT(jcr->VolumeName);
+           break;
+         case 'f':
+           str = NPRT(jcr->client_name);
+           break;
+
+        default:
+            add[0] = '%';
+           add[1] = *p;
+           add[2] = 0;
+           str = add;
+           break;
+        }
+      } else {
+        add[0] = *p;
+        add[1] = 0;
+        str = add;
+      }
+      Dmsg1(200, "add_str %s\n", str);
+      pm_strcat(&omsg, (char *)str);
+      Dmsg1(200, "omsg=%s\n", omsg);
+   }
+   return omsg;
+}
index 016bd440aaab044ef212694dd9741b099c46112a..fdabb03f56bfd5f5f055243b466f6de712a1cc49 100644 (file)
@@ -68,6 +68,7 @@ static int cancel_cmd(JCR *cjcr);
 static int mount_cmd(JCR *jcr);
 static int unmount_cmd(JCR *jcr);
 static int status_cmd(JCR *sjcr);
+static int autochanger_cmd(JCR *sjcr);
 static int do_label(JCR *jcr, int relabel);
 static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
                               char *newname, char *poolname, 
@@ -91,6 +92,7 @@ static struct s_cmds cmds[] = {
    {"mount",     mount_cmd},
    {"unmount",   unmount_cmd},
    {"status",    status_cmd},
+   {"autochanger", autochanger_cmd},
    {NULL,       NULL}                /* list terminator */
 };
 
@@ -801,3 +803,69 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev)
         break;
    }
 }
+
+/*
+ * Autochanger command from Director
+ */
+static int autochanger_cmd(JCR *jcr)
+{
+   char *devname;
+   BSOCK *dir = jcr->dir_bsock;
+   DEVRES *device;
+   DEVICE *dev;
+   int found = 0;
+
+   devname = (char *)get_memory(dir->msglen);
+   if (sscanf(dir->msg, "autochanger list %s ", devname) == 1) {
+      unbash_spaces(devname);
+      device = NULL;
+      LockRes();
+      while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
+        /* Find resource, and make sure we were able to open it */
+        if (strcmp(device->hdr.name, devname) == 0 && device->dev) {
+            Dmsg1(20, "Found device %s\n", device->hdr.name);
+           found = 1;
+           break;
+        }
+      }
+      UnlockRes();
+      if (found) {
+        jcr->device = device;
+        dev = device->dev;
+        P(dev->mutex);               /* Use P to avoid indefinite block */
+        if (!(dev->state & ST_OPENED)) {
+           if (open_dev(dev, NULL, READ_WRITE) < 0) {
+               bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
+           } else {
+              autochanger_list(jcr, dev, dir);
+              force_close_dev(dev);
+           }
+         /* Under certain "safe" conditions, we can steal the lock */
+        } else if (dev->dev_blocked && 
+                   (dev->dev_blocked == BST_UNMOUNTED ||
+                    dev->dev_blocked == BST_WAITING_FOR_SYSOP ||
+                    dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) {
+           autochanger_list(jcr, dev, dir);
+        } else if (dev->state & ST_READ || dev->num_writers) {
+           if (dev->state & ST_READ) {
+                bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
+                  dev_name(dev));
+           } else {
+                bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
+                  dev_name(dev), dev->num_writers);
+           }
+        } else {                     /* device not being used */
+           autochanger_list(jcr, dev, dir);
+        }
+        V(dev->mutex);
+      } else {
+         bnet_fsend(dir, _("3999 Device %s not found\n"), devname);
+      }
+   } else {
+      strcpy(devname, dir->msg);
+      bnet_fsend(dir, _("3907 Error scanning autocharger list command: %s\n"), devname);
+   }
+   free_memory(devname);
+   bnet_sig(dir, BNET_EOD);
+   return 1;
+}
index abedacf060f120b51b00bc6bf0430ae962f270fc..dc0f5179ad6880bfbfbc98511d064ae809c5cc05 100644 (file)
@@ -31,7 +31,6 @@
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
 /* Forward referenced functions */
-static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd);
 
 
 /*
@@ -378,186 +377,3 @@ int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    Dmsg0(90, "End of Device reached.\n");
    return 0;
 }
-
-/*
- * Called here to do an autoload using the autochanger, if
- *  configured, and if a Slot has been defined for this Volume.
- *  On success this routine loads the indicated tape, but the
- *  label is not read, so it must be verified.
- *
- *  Note if dir is not NULL, it is the console requesting the 
- *   autoload for labeling, so we respond directly to the
- *   dir bsock.
- *
- *  Returns: 1 on success
- *          0 on failure
- */
-int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir)
-{
-   int slot = jcr->VolCatInfo.Slot;
-   int rtn_stat = 0;
-     
-   /*
-    * Handle autoloaders here. If we cannot autoload it, we
-    *  will return FALSE to ask the sysop.
-    */
-   if (writing && dev_cap(dev, CAP_AUTOCHANGER) && slot <= 0) {
-      if (dir) {
-        return 0;                    /* For user, bail out right now */
-      }
-      if (dir_find_next_appendable_volume(jcr)) {
-        slot = jcr->VolCatInfo.Slot; 
-      }
-   }
-   Dmsg1(100, "Want changer slot=%d\n", slot);
-
-   if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) {
-      uint32_t timeout = jcr->device->max_changer_wait;
-      POOLMEM *changer, *results;
-      int status, loaded;
-
-      results = get_pool_memory(PM_MESSAGE);
-      changer = get_pool_memory(PM_FNAME);
-
-      /* Find out what is loaded, zero means device is unloaded */
-      changer = edit_device_codes(jcr, changer, jcr->device->changer_command, 
-                   "loaded");
-      status = run_program(changer, timeout, results);
-      Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results);
-      if (status == 0) {
-        loaded = atoi(results);
-      } else {
-        loaded = -1;              /* force unload */
-      }
-      Dmsg1(100, "loaded=%s\n", results);
-
-      /* If bad status or tape we want is not loaded, load it. */
-      if (status != 0 || loaded != slot) { 
-        if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
-           offline_dev(dev);
-        }
-        /* We are going to load a new tape, so close the device */
-        force_close_dev(dev);
-        if (loaded != 0) {        /* must unload drive */
-            Dmsg0(100, "Doing changer unload.\n");
-           if (dir) {
-               bnet_fsend(dir, _("3902 Issuing autochanger \"unload\" command.\n"));
-           } else {
-               Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"unload\" command.\n"));
-           }
-           changer = edit_device_codes(jcr, changer, 
-                        jcr->device->changer_command, "unload");
-           status = run_program(changer, timeout, NULL);
-            Dmsg1(100, "unload status=%d\n", status);
-        }
-        /*
-         * Load the desired cassette    
-         */
-         Dmsg1(100, "Doing changer load slot %d\n", slot);
-        if (dir) {
-            bnet_fsend(dir, _("3903 Issuing autochanger \"load slot %d\" command.\n"),
-              slot);
-        } else {
-            Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"load slot %d\" command.\n"),
-              slot);
-        }
-        changer = edit_device_codes(jcr, changer, 
-                      jcr->device->changer_command, "load");
-        status = run_program(changer, timeout, NULL);
-        if (status == 0) {
-            Jmsg(jcr, M_INFO, 0, _("Autochanger \"load slot\" status is OK.\n"));
-        } else {
-            Jmsg(jcr, M_INFO, 0, _("Bad autochanger \"load slot\" status = %d.\n"),
-              status);
-        }
-         Dmsg2(100, "load slot %d status=%d\n", slot, status);
-      }
-      free_pool_memory(changer);
-      free_pool_memory(results);
-      Dmsg1(100, "After changer, status=%d\n", status);
-      if (status == 0) {          /* did we succeed? */
-        rtn_stat = 1;             /* tape loaded by changer */
-      }
-   }
-   return rtn_stat;
-}
-
-
-
-/*
- * Edit codes into ChangerCommand
- *  %% = %
- *  %a = archive device name
- *  %c = changer device name
- *  %f = Client's name
- *  %j = Job name
- *  %o = command
- *  %s = Slot base 0
- *  %S = Slot base 1
- *  %v = Volume name
- *
- *
- *  omsg = edited output message
- *  imsg = input string containing edit codes (%x)
- *  cmd = command string (load, unload, ...) 
- *
- */
-static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) 
-{
-   char *p;
-   const char *str;
-   char add[20];
-
-   *omsg = 0;
-   Dmsg1(200, "edit_device_codes: %s\n", imsg);
-   for (p=imsg; *p; p++) {
-      if (*p == '%') {
-        switch (*++p) {
-         case '%':
-            str = "%";
-           break;
-         case 'a':
-           str = jcr->device->dev->dev_name;
-           break;
-         case 'c':
-           str = NPRT(jcr->device->changer_name);
-           break;
-         case 'o':
-           str = NPRT(cmd);
-           break;
-         case 's':
-            sprintf(add, "%d", jcr->VolCatInfo.Slot - 1);
-           str = add;
-           break;
-         case 'S':
-            sprintf(add, "%d", jcr->VolCatInfo.Slot);
-           str = add;
-           break;
-         case 'j':                    /* Job name */
-           str = jcr->Job;
-           break;
-         case 'v':
-           str = NPRT(jcr->VolumeName);
-           break;
-         case 'f':
-           str = NPRT(jcr->client_name);
-           break;
-
-        default:
-            add[0] = '%';
-           add[1] = *p;
-           add[2] = 0;
-           str = add;
-           break;
-        }
-      } else {
-        add[0] = *p;
-        add[1] = 0;
-        str = add;
-      }
-      Dmsg1(200, "add_str %s\n", str);
-      pm_strcat(&omsg, (char *)str);
-      Dmsg1(200, "omsg=%s\n", omsg);
-   }
-   return omsg;
-}
index a75a16055fd2fdcf027a0beba061c07968d071f6..693ce620c56b3c91835f75a1449a38784f4016c5 100644 (file)
 uint32_t new_VolSessionId();
 
 /* From acquire.c */
-DEVICE  *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int      acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int      release_device(JCR *jcr, DEVICE *dev);
+DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     release_device(JCR *jcr, DEVICE *dev);
 
 /* From askdir.c */
-int     dir_get_volume_info(JCR *jcr, int writing);
-int     dir_find_next_appendable_volume(JCR *jcr);
-int     dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel);
-int     dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev);
-int     dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
-int     dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
-int     dir_send_job_status(JCR *jcr);
-int     dir_create_jobmedia_record(JCR *jcr);
+int    dir_get_volume_info(JCR *jcr, int writing);
+int    dir_find_next_appendable_volume(JCR *jcr);
+int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel);
+int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev);
+int    dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
+int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
+int    dir_send_job_status(JCR *jcr);
+int    dir_create_jobmedia_record(JCR *jcr);
 
 /* authenticate.c */
-int     authenticate_director(JCR *jcr);
-int     authenticate_filed(JCR *jcr);
+int    authenticate_director(JCR *jcr);
+int    authenticate_filed(JCR *jcr);
 
 /* From block.c */
-void    dump_block(DEV_BLOCK *b, char *msg);
+void   dump_block(DEV_BLOCK *b, char *msg);
 DEV_BLOCK *new_block(DEVICE *dev);
-void    init_block_write(DEV_BLOCK *block);
-void    empty_block(DEV_BLOCK *block);
-void    free_block(DEV_BLOCK *block);
-int     write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int     write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int     read_block_from_device(DEVICE *dev, DEV_BLOCK *block);
-int     read_block_from_dev(DEVICE *dev, DEV_BLOCK *block);
+void   init_block_write(DEV_BLOCK *block);
+void   empty_block(DEV_BLOCK *block);
+void   free_block(DEV_BLOCK *block);
+int    write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int    write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int    read_block_from_device(DEVICE *dev, DEV_BLOCK *block);
+int    read_block_from_dev(DEVICE *dev, DEV_BLOCK *block);
 
 /* From butil.c -- utilities for SD tool programs */
-void    print_ls_output(char *fname, char *link, int type, struct stat *statp);
+void   print_ls_output(char *fname, char *link, int type, struct stat *statp);
 JCR    *setup_jcr(char *name, char *device, BSR *bsr, char *VolumeName);
 DEVICE *setup_to_access_device(JCR *jcr, int read_access);
-void    display_error_status(DEVICE *dev);
+void   display_error_status(DEVICE *dev);
 DEVRES *find_device_res(char *device_name, int read_access);
 
 
 /* From dev.c */
-DEVICE  *init_dev(DEVICE *dev, DEVRES *device);
-int      open_dev(DEVICE *dev, char *VolName, int mode);
-void     close_dev(DEVICE *dev);
-void     force_close_dev(DEVICE *dev);
-int      truncate_dev(DEVICE *dev);
-void     term_dev(DEVICE *dev);
-char *   strerror_dev(DEVICE *dev);
-void     clrerror_dev(DEVICE *dev, int func);
-int      update_pos_dev(DEVICE *dev);
-int      rewind_dev(DEVICE *dev);
-int      load_dev(DEVICE *dev);
-int      offline_dev(DEVICE *dev);
-int      flush_dev(DEVICE *dev);
-int      weof_dev(DEVICE *dev, int num);
-int      write_block(DEVICE *dev);
-int      write_dev(DEVICE *dev, char *buf, size_t len);
-int      read_dev(DEVICE *dev, char *buf, size_t len);
-int      status_dev(DEVICE *dev, uint32_t *status);
-int      eod_dev(DEVICE *dev);
-int      fsf_dev(DEVICE *dev, int num);
-int      fsr_dev(DEVICE *dev, int num);
-int      bsf_dev(DEVICE *dev, int num);
-int      bsr_dev(DEVICE *dev, int num);
-void     attach_jcr_to_device(DEVICE *dev, JCR *jcr);
-void     detach_jcr_from_device(DEVICE *dev, JCR *jcr);
-JCR     *next_attached_jcr(DEVICE *dev, JCR *jcr);
+DEVICE *init_dev(DEVICE *dev, DEVRES *device);
+int     open_dev(DEVICE *dev, char *VolName, int mode);
+void    close_dev(DEVICE *dev);
+void    force_close_dev(DEVICE *dev);
+int     truncate_dev(DEVICE *dev);
+void    term_dev(DEVICE *dev);
+char *  strerror_dev(DEVICE *dev);
+void    clrerror_dev(DEVICE *dev, int func);
+int     update_pos_dev(DEVICE *dev);
+int     rewind_dev(DEVICE *dev);
+int     load_dev(DEVICE *dev);
+int     offline_dev(DEVICE *dev);
+int     flush_dev(DEVICE *dev);
+int     weof_dev(DEVICE *dev, int num);
+int     write_block(DEVICE *dev);
+int     write_dev(DEVICE *dev, char *buf, size_t len);
+int     read_dev(DEVICE *dev, char *buf, size_t len);
+int     status_dev(DEVICE *dev, uint32_t *status);
+int     eod_dev(DEVICE *dev);
+int     fsf_dev(DEVICE *dev, int num);
+int     fsr_dev(DEVICE *dev, int num);
+int     bsf_dev(DEVICE *dev, int num);
+int     bsr_dev(DEVICE *dev, int num);
+void    attach_jcr_to_device(DEVICE *dev, JCR *jcr);
+void    detach_jcr_from_device(DEVICE *dev, JCR *jcr);
+JCR    *next_attached_jcr(DEVICE *dev, JCR *jcr);
 
 
 /* Get info about device */
-char *   dev_name(DEVICE *dev);
-char *   dev_vol_name(DEVICE *dev);
+char *  dev_name(DEVICE *dev);
+char *  dev_vol_name(DEVICE *dev);
 uint32_t dev_block(DEVICE *dev);
 uint32_t dev_file(DEVICE *dev);
-int      dev_is_tape(DEVICE *dev);
+int     dev_is_tape(DEVICE *dev);
 
 /* From device.c */
-int      open_device(DEVICE *dev);
-int      fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int     open_device(DEVICE *dev);
+int     fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
 void _lock_device(char *file, int line, DEVICE *dev);
 void _unlock_device(char *file, int line, DEVICE *dev);
 void _block_device(char *file, int line, DEVICE *dev, int state);
@@ -119,40 +119,43 @@ void  new_steal_device_lock(DEVICE *dev, brwsteal_t *hold, int state);
 void  new_return_device_lock(DEVICE *dev, brwsteal_t *hold);
 
 /* From dircmd.c */
-void     *connection_request(void *arg); 
+void    *connection_request(void *arg); 
 
 
 /* From fd_cmds.c */
-void     run_job(JCR *jcr);
+void    run_job(JCR *jcr);
 
 /* From fdmsg.c */
-int      bget_msg(BSOCK *sock);
+int     bget_msg(BSOCK *sock);
 
 /* From job.c */
-void     stored_free_jcr(JCR *jcr);
-void     connection_from_filed(void *arg);     
-void     handle_filed_connection(BSOCK *fd, char *job_name);
+void    stored_free_jcr(JCR *jcr);
+void    connection_from_filed(void *arg);     
+void    handle_filed_connection(BSOCK *fd, char *job_name);
 
 /* From label.c */
-int      read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void     create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
-void     create_volume_label(DEVICE *dev, char *VolName);
-int      write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
-int      write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
-int      write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void     dump_volume_label(DEVICE *dev);
-void     dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
-int      unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
-int      unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
+int     read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
+void    create_volume_label(DEVICE *dev, char *VolName);
+int     write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
+int     write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
+int     write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void    dump_volume_label(DEVICE *dev);
+void    dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
+int     unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
+int     unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
 
 /* From match_bsr.c */
 int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, 
-              SESSION_LABEL *sesrec);
+             SESSION_LABEL *sesrec);
 
 /* From mount.c */
-int      mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
-int      mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int      autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
+int     mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
+int     mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+
+/* From autochanger.c */
+int     autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
+int     autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
 
 
 /* From parse_bsr.c */
@@ -167,11 +170,11 @@ extern void create_vol_list(JCR *jcr);
 /* From record.c */
 char   *FI_to_ascii(int fi);
 char   *stream_to_ascii(int stream, int fi);
-int     write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int     can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int     read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); 
+int    write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int    can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int    read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); 
 DEV_RECORD *new_record();
-void    free_record(DEV_RECORD *rec);
+void   free_record(DEV_RECORD *rec);
 
 /* From read_record.c */
 int read_records(JCR *jcr,  DEVICE *dev,