]> git.sur5r.net Git - bacula/bacula/commitdiff
Add auto-changer support -- kes17Jul02
authorKern Sibbald <kern@sibbald.com>
Wed, 17 Jul 2002 16:42:02 +0000 (16:42 +0000)
committerKern Sibbald <kern@sibbald.com>
Wed, 17 Jul 2002 16:42:02 +0000 (16:42 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@58 91ce42f0-d328-0410-95d8-f526ca767f89

13 files changed:
bacula/src/cats/make_mysql_tables.in
bacula/src/cats/sql_find.c
bacula/src/cats/sql_get.c
bacula/src/dird/catreq.c
bacula/src/dird/ua_cmds.c
bacula/src/lib/protos.h
bacula/src/lib/util.c
bacula/src/stored/askdir.c
bacula/src/stored/dev.c
bacula/src/stored/device.c
bacula/src/stored/stored_conf.c
bacula/src/stored/stored_conf.h
bacula/src/version.h

index d02c9e128a9efa7cb706fd26fb37533db3da7476..22acc913f7db1f7d1d8bcdfda0d4bdf00f55701d 100644 (file)
@@ -89,7 +89,7 @@ CREATE TABLE JobMedia (
 CREATE TABLE Media (
    MediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
    VolumeName TINYBLOB NOT NULL,
-   Slot INTEGER NOT NULL,
+   Slot INTEGER NOT NULL DEFAULT 0,
    PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool,
    MediaType TINYBLOB NOT NULL,
    FirstWritten DATETIME NOT NULL,
index 7da8ecd7b7aad6125275749653c6ceaa10252469..45d75e14a39d0fe7ac25c16dd548819f7e197819 100644 (file)
@@ -204,7 +204,7 @@ db_find_next_volume(B_DB *mdb, int item, MEDIA_DBR *mr)
 
    db_lock(mdb);
    Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
-VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes \
+VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,Slot \
 FROM Media WHERE PoolId=%d AND MediaType=\"%s\" AND VolStatus=\"%s\" \
 ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); 
 
@@ -245,6 +245,7 @@ ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus);
    mr->VolWrites = atoi(row[8]);
    mr->VolMaxBytes = (uint64_t)strtod(row[9], NULL);
    mr->VolCapacityBytes = (uint64_t)strtod(row[10], NULL);
+   mr->Slot = atoi(row[11]);
 
    sql_free_result(mdb);
 
index 8d26335ffa046f154bf76053bf07d65ca9b72fd0..2a7e46225b11418e6d7a83285a856f670d9220f3 100644 (file)
@@ -584,12 +584,12 @@ int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr)
    if (mr->MediaId != 0) {              /* find by id */
       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
 VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
-MediaType,VolStatus,PoolId,VolRetention,Recycle \
+MediaType,VolStatus,PoolId,VolRetention,Recycle,Slot \
 FROM Media WHERE MediaId=%d", mr->MediaId);
    } else {                          /* find by name */
       Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\
 VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\
-MediaType,VolStatus,PoolId,VolRetention,Recycle \
+MediaType,VolStatus,PoolId,VolRetention,Recycle,Slot \
 FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName);
    }  
 
@@ -620,6 +620,7 @@ FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName);
            mr->PoolId = atoi(row[13]);
            mr->VolRetention = (btime_t)strtod(row[14], NULL);
            mr->Recycle = atoi(row[15]);
+           mr->Slot = atoi(row[16]);
            stat = mr->MediaId;
         }
       } else {
index 2a249361e14b0fe353a68336e6c444f6074b6039..cf4d2dc85424fb4b196fe18f2a4013b53b87a693 100644 (file)
@@ -147,7 +147,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg)
            bnet_fsend(bs, OK_media, mr.VolumeName, mr.VolJobs,
               mr.VolFiles, mr.VolBlocks, mr.VolBytes, mr.VolMounts, mr.VolErrors,
               mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes,
-              mr.VolStatus);
+              mr.VolStatus, mr.Slot);
         } else { 
             Dmsg4(100, "get_media_record PoolId=%d wanted %d, Status=%s, \
 MediaType=%s\n", mr.PoolId, jcr->PoolId, mr.VolStatus, mr.MediaType);
index 6b4e399eaf5e328cc60d6ba18d61670cfb0c1247..83228fff2b6e72a99370f858eac660730a83ff2f 100644 (file)
@@ -592,17 +592,18 @@ static int update_volume(UAContext *ua)
       }
       strcpy(mr.VolumeName, ua->cmd);
    }
-   mr.MediaId = 0;
-   if (!db_get_media_record(ua->db, &mr)) {
-      bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName);
-      return 0;
-   }
 
    for (int done=0; !done; ) {
+      mr.MediaId = 0;
+      if (!db_get_media_record(ua->db, &mr)) {
+         bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName);
+        return 0;
+      }
       start_prompt(ua, _("Parameters to modify:\n"));
       add_prompt(ua, _("Volume Status"));
       add_prompt(ua, _("Volume Retention Period"));
       add_prompt(ua, _("Recycle Flag"));
+      add_prompt(ua, _("Slot"));
       add_prompt(ua, _("Done"));
       switch (do_prompt(ua, _("Select paramter to modify"), NULL)) {
       case 0:                        /* Volume Status */
@@ -670,9 +671,37 @@ static int update_volume(UAContext *ua)
         }       
         free_pool_memory(query);
         break;
+
+      case 3:                        /* Slot */
+        int slot;
+         bsendmsg(ua, _("Current value is: %d\n"), mr.Slot);
+         if (!get_cmd(ua, _("Enter new Slot: "))) {
+           return 0;
+        }
+        slot = atoi(ua->cmd);
+        if (slot < 0) {
+            bsendmsg(ua, _("Invalid slot, it must be 0 or greater\n"));
+           break;
+        } else if (pr.MaxVols > 0 && slot >(int)pr.MaxVols) {
+            bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
+              pr.MaxVols);
+           break;
+        }
+        query = get_pool_memory(PM_MESSAGE);
+         Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%d",
+           slot, mr.MediaId);
+        if (!db_sql_query(ua->db, query, NULL, NULL)) {  
+            bsendmsg(ua, "%s", db_strerror(ua->db));
+        } else {
+            bsendmsg(ua, "New value is: %d\n", slot);
+        }
+        free_pool_memory(query);
+        break;
+
         
       default:                       /* Done or error */
-        return 0;
+         bsendmsg(ua, "Selection done.\n");
+        return 1;
       }
    }
    return 1;
index 65b2d8247e49e9e1466d06c8866e69ac6a014414..c461784ce13bf99bbed6ea3e53f4e55c5bf17301 100644 (file)
@@ -151,6 +151,7 @@ int              string_to_btime         (char *str, btime_t *value);
 char             *edit_btime             (btime_t val, char *buf);
 void             jobstatus_to_ascii      (int JobStatus, char *msg, int maxlen);
 void             add_str_to_pool_mem     (POOLMEM **base, char **msg, char *str);
+int              run_program             (char *prog, int wait, POOLMEM *results);
 
 
 /*
index 0d467d7c545bf2e383725b57ee6e766317f26391..44f4e026a8664d9e948581535c363bc06ebcf81c 100644 (file)
@@ -547,3 +547,134 @@ int do_shell_expansion(char *name)
 #endif
 
 }
+
+#define MAX_ARGV 100
+static char *bargv[MAX_ARGV];
+static int bargc;
+static void build_argc_argv(char *cmd);
+
+int run_program(char *prog, int wait, POOLMEM *results)
+{
+   int stat = ETIME;
+   int chldstatus = 0;
+   pid_t pid1, pid2;
+   int pfd[2];
+   int i;
+
+   
+   build_argc_argv(prog);
+#ifdef lots_of_debug
+   printf("argc=%d\n", bargc);
+   for (i=0; i<bargc; i++) {
+      printf("argc=%d argv=%s\n", i, bargv[i]);
+   }
+#endif
+
+   if (results && pipe(pfd) == -1) {
+      return errno;
+   }
+   /* Start worker process */
+   switch (pid1 = fork()) {
+   case -1:
+      break;
+
+   case 0:                           /* child */
+//    printf("execl of %s\n", prog);
+      if (results) {
+        close(1); dup(pfd[1]);       /* attach pipes to stdin and stdout */
+        close(2); dup(pfd[1]);
+      }
+      execvp(bargv[0], bargv);
+      exit(errno);                   /* shouldn't get here */
+
+   default:                          /* parent */
+      /* start timer process */
+      switch (pid2=fork()) {
+      case -1:
+        break;
+      case 0:                        /* child 2 */
+        /* Time the worker process */  
+        sleep(wait);
+        if (kill(pid1, SIGTERM) == 0) { /* time expired kill it */
+           exit(0);
+        }
+        sleep(3);
+        kill(pid1, SIGKILL);
+        exit(0);
+      default:                       /* parent */
+        int i;
+        if (results) {
+           i = read(pfd[0], results, sizeof_pool_memory(results) - 1);
+           if (--i < 0) {
+              i = 0;
+           }
+           results[i] = 0;                /* set end of string */
+        }
+        /* wait for worker child to exit */
+        for ( ;; ) {
+           pid_t wpid;
+           wpid = waitpid(pid1, &chldstatus, 0);         
+           if (wpid == pid1 || (errno != EINTR)) {
+              break;
+           }
+        }
+        if (WIFEXITED(chldstatus))
+           stat = WEXITSTATUS(chldstatus);
+
+        kill(pid2, SIGKILL);           /* kill off timer process */
+        waitpid(pid2, &chldstatus, 0); /* reap timer process */
+        if (results) { 
+           close(pfd[0]);              /* close pipe */
+           close(pfd[1]);
+        }
+        break;
+      }
+      break;
+   }
+   return stat;
+}
+
+/*
+ * Build argc and argv from a string
+ */
+static void build_argc_argv(char *cmd)
+{
+   int i, quote;
+   char *p, *q;
+
+   bargc = 0;
+   for (i=0; i<MAX_ARGV; i++)
+      bargv[i] = NULL;
+
+   p = cmd;
+   quote = 0;
+   while  (*p && (*p == ' ' || *p == '\t'))
+      p++;
+   if (*p == '\"') {
+      quote = 1;
+      p++;
+   }
+   if (*p) {
+      while (*p && bargc < MAX_ARGV) {
+        q = p;
+        if (quote) {
+            while (*q && *q != '\"')
+           q++;
+           quote = 0;
+        } else {
+            while (*q && *q != ' ')
+           q++;
+        }
+        if (*q)
+            *(q++) = '\0';
+        bargv[bargc++] = p;
+        p = q;
+         while (*p && (*p == ' ' || *p == '\t'))
+           p++;
+         if (*p == '\"') {
+           quote = 1;
+           p++;
+        }
+      }
+   }
+}
index 78f7f1840d1e678d0966c107bfa64994a69c8f18..4d4d86ce8dfa960e8fa00f3b6411c44134725b81 100644 (file)
@@ -95,7 +95,8 @@ static int do_request_volume_info(JCR *jcr)
     unbash_spaces(vol->VolCatName);
     strcpy(jcr->VolumeName, vol->VolCatName); /* set desired VolumeName */
     
-    Dmsg1(200, "Got Volume=%s\n", vol->VolCatName);
+    Dmsg2(030, "do_reqest_vol_info got slot=%d Volume=%s\n", 
+       vol->Slot, vol->VolCatName);
     return 1;
 }
 
index 207637983aa91eebabe6866e1a6da5de1c6207c5..286de5a63ef3ebdfc81598f3dc3d524c6d169114 100644 (file)
@@ -579,7 +579,7 @@ int offline_dev(DEVICE *dev)
         dev->dev_name, strerror(dev->dev_errno));
       return 0;
    }
-   Dmsg1(000, "Offlined device %s\n", dev->dev_name);
+   Dmsg1(100, "Offlined device %s\n", dev->dev_name);
    return 1;
 }
 
index 20abc6c4933a805781d6dc7014be61aa069013b9..118862f448791a59d088f324d02ed0b01e2fadc7 100644 (file)
@@ -53,6 +53,7 @@
 
 /* Forward referenced functions */
 static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *label_blk, int release);
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd);
 
 extern char my_name[];
 extern int debug_level;
@@ -178,7 +179,7 @@ int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
       if (!dev_is_tape(dev)) {
         close_dev(dev);
       }
-      /******FIXME**** send read volume info to director */
+      /******FIXME**** send read volume usage statistics to director */
 
    } else if (dev->num_writers > 0) {
       dev->num_writers--;
@@ -220,11 +221,15 @@ int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
  */
 static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release)
 {
-   int recycle, ask;
+   int recycle, ask, retry = 0;
 
    Dmsg0(90, "Enter mount_next_volume()\n");
 
 mount_next_vol:
+   if (retry++ > 5) {
+      Mmsg0(&dev->errmsg, _("Too many retries.\n"));
+      return 0;
+   }
    if (job_cancelled(jcr)) {
       Mmsg0(&dev->errmsg, _("Job cancelled.\n"));
       return 0;
@@ -281,17 +286,72 @@ mount_next_vol:
 
    jcr->VolFirstFile = 0;            /* first update of Vol FileIndex */
    for ( ;; ) {
+      int slot = jcr->VolCatInfo.Slot;
+       
+      /*
+       * Handle autoloaders here.  If we cannot autoload it, we
+       *  will fall through to ask the sysop.
+       */
+      if (dev->capabilities && CAP_AUTOCHANGER && slot <= 0) {
+        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->changer_timeout;
+        POOLMEM *changer, *results;
+        int status, loaded;
+
+        results = get_pool_memory(PM_MESSAGE);
+        changer = get_pool_memory(PM_FNAME);
+        /* Find out what is loaded */
+        changer = edit_device_codes(jcr, changer, jcr->device->changer_command, 
+                      "loaded");
+        status = run_program(changer, timeout, results);
+        if (status == 0) {
+           loaded = atoi(results);
+        } else {
+           loaded = -1;              /* force unload */
+        }
+         Dmsg1(100, "loaded=%s\n", results);
 
-      Dmsg1(000, "Have changer. Dev=%s\n", NPRT(jcr->device->changer_name));
-      if (ask) {
-        if (dev->capabilities && CAP_AUTOCHANGER) {
-            Dmsg1(000, "Have changer. Dev=%s\n", NPRT(jcr->device->changer_name));
- /*** ****FIXME**** add changer code here */
+        /* If bad status or tape we want is not loaded, load it. */
+        if (status != 0 || loaded != slot) { 
+           if (dev->capabilities & 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");
+              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);
+           changer = edit_device_codes(jcr, changer, 
+                         jcr->device->changer_command, "load");
+           status = run_program(changer, timeout, NULL);
+            Dmsg2(100, "load slot %d status=%d\n", slot, status);
         }
-        if (!dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
-           return 0;              /* error return */
+        free_pool_memory(changer);
+        free_pool_memory(results);
+         Dmsg1(100, "After changer, status=%d\n", status);
+        if (status == 0) {           /* did we succeed? */
+           ask = 0;                  /* yes, got vol, no need to ask sysop */
         }
       }
+
+
+      if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
+        return 0;              /* error return */
+      }
       Dmsg1(200, "want vol=%s\n", jcr->VolumeName);
 
       /* Open device */
@@ -732,7 +792,7 @@ void unblock_device(DEVICE *dev)
 
 
 /*
- * Edit codes into ChangerDevice
+ * Edit codes into ChangerCommand
  *  %% = %
  *  %a = archive device name
  *  %c = changer device name
@@ -749,9 +809,10 @@ void unblock_device(DEVICE *dev)
  *  cmd = command string (load, unload, ...) 
  *
  */
-char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) 
+static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) 
 {
-   char *p, *o, *str;
+   char *p, *o;
+   const char *str;
    char add[20];
 
    Dmsg1(200, "edit_job_codes: %s\n", imsg);
@@ -769,17 +830,17 @@ char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd)
            str = jcr->device->dev->dev_name;
            break;
          case 'c':
-           str = jcr->device->changer_name;
+           str = NPRT(jcr->device->changer_name);
            break;
          case 'o':
-           str = cmd;
+           str = NPRT(cmd);
            break;
          case 's':
-            sprintf(add, "%d", jcr->device->dev->VolCatInfo.Slot - 1);
+            sprintf(add, "%d", jcr->VolCatInfo.Slot - 1);
            str = add;
            break;
          case 'S':
-            sprintf(add, "%d", jcr->device->dev->VolCatInfo.Slot);
+            sprintf(add, "%d", jcr->VolCatInfo.Slot);
            str = add;
            break;
          case 'j':                    /* Job name */
@@ -810,7 +871,7 @@ char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd)
         str = add;
       }
       Dmsg1(200, "add_str %s\n", str);
-      add_str_to_pool_mem(&omsg, &o, str);
+      add_str_to_pool_mem(&omsg, &o, (char *)str);
       *o = 0;
       Dmsg1(200, "omsg=%s\n", omsg);
    }
index 36acfce9bb59739c65071f67593b40c0399480cb..1e2f58117f5237974ad651091603ee320c9d94a8 100644 (file)
@@ -95,6 +95,8 @@ static struct res_items dev_items[] = {
    {"alwaysopen",            store_yesno,  ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
    {"autochanger",           store_yesno,  ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
    {"changerdevice",         store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
+   {"changercommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
+   {"changertimeout",        store_pint,   ITEM(res_dev.changer_timeout), 0, ITEM_DEFAULT, 60},
    {"offlineonunmount",      store_yesno,  ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 1},
    {"maximumrewindwait",     store_pint,   ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
    {"minimumblocksize",      store_pint,   ITEM(res_dev.min_block_size), 0, 0, 0},
@@ -259,6 +261,8 @@ void free_resource(int type)
            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)
index 8983a82036282c2ef7d49157bdbec24af1d44cf4..8e8c9cca548d71f7cb2f78e4b1670687aa7a4676 100644 (file)
@@ -73,7 +73,9 @@ struct s_res_dev {
    char *media_type;                 /* User assigned media type */
    char *device_name;                /* Archive device name */
    char *changer_name;               /* Changer device name */
+   char *changer_command;            /* Changer command  -- external program */
    int cap_bits;                     /* Capabilities of this device */
+   uint32_t changer_timeout;         /* Changer timeout */
    uint32_t max_rewind_wait;         /* maximum secs to wait for rewind */
    uint32_t min_block_size;          /* min block size */
    uint32_t max_block_size;          /* max block size */
index f2cb7d0f1bde762b41cdc50262c6fc0ff583bf0f..5a6f3c2df87ddf2e69c762838232576ad17b2f3e 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #define VERSION "1.23"
 #define VSTRING "1"
-#define DATE    "15 July 2002"
-#define LSMDATE "15Jul02"
+#define DATE    "16 July 2002"
+#define LSMDATE "16Jul02"
 
 /* Debug flags */
 #define DEBUG 1