- Figure out how to use ssh or stunnel to protect Bacula communications.
 
 For 1.33 Testing/Documentation:
+- Document new alias records in Director. SDAddress SDDeviceName, SDPassword.
+  FDPassword, FDAddress, DBAddress, DBPort, DBPassword.
+- Document new Include/Exclude ...
+- Add test of exclusion, test multiple Include {} statements.
+- Add counter variable test.
+- Document ln -sf /usr/lib/libncurses.so /usr/lib/libtermcap.so
+  and install the esound-dev  package for compiling Console on SuSE.
+- Add an example of using a FIFO in dirdconf.wml 
+- Add an item to the FAQ about running jobs in different timezones.
+- Add some examples of job editing codes.
+- Add Dan's 31 Oct 2003 email on tcpwrappers to Tips.
+- Add to supported autochangers 
+  OS              : FreeBSD-4.9
+  Auto-Changer    : QUALSTAR TLS-4210
+    Manufufactur  : Qualstar
+    Tapes         : 12 (AIT1: 36GB, AIT2: 50GB all uncompressed)
+    Drives        : 2xAIT2 (installed in the Qualstar: SONY SDX-500C AIT2)
+- Setup a standard job that builds a bootstrap file and saves
+  it with the catalog database.
+- Document Dan's new --with-dir-user, ... options.
+                
+
+For 1.33
+- Add a default DB password to MySQL.  
+  GRANT all privileges ON bacula.* TO bacula@localhost IDENTIFIED BY 
+     'bacula_password';
+  FLUSH PRIVILEGES;
 - Define week of year for scheduler.  W01, W02, ...
   Week 01 of a year is per definition the first week that has the
   Thursday in this year, which is equivalent to the week that contains the
   it to tape.
 - Scratch Pool where the volumes can be re-assigned to any Pool.
 - bextract is sending everything to the log file ****FIXME****
-- Document new alias records in Director. SDAddress SDDeviceName, SDPassword.
-  FDPassword, FDAddress, DBAddress, DBPort, DBPassword.
-- Document new Include/Exclude ...
-- Add test of exclusion, test multiple Include {} statements.
-- Add counter variable test.
-- Document ln -sf /usr/lib/libncurses.so /usr/lib/libtermcap.so
-  and install the esound-dev  package for compiling Console on SuSE.
-- Add an example of using a FIFO in dirdconf.wml 
-- Add an item to the FAQ about running jobs in different timezones.
-- Add some examples of job editing codes.
-- Add Dan's 31 Oct 2003 email on tcpwrappers to Tips.
-- Add to supported autochangers 
-  OS              : FreeBSD-4.9
-  Auto-Changer    : QUALSTAR TLS-4210
-    Manufufactur  : Qualstar
-    Tapes         : 12 (AIT1: 36GB, AIT2: 50GB all uncompressed)
-    Drives        : 2xAIT2 (installed in the Qualstar: SONY SDX-500C AIT2)
-- Setup a standard job that builds a bootstrap file and saves
-  it with the catalog database.
-- Document Dan's new --with-dir-user, ... options.
-                
-For 1.33
 - Add Progress command that periodically reports the progress of
   a job or all jobs.
 - Restrict characters permitted in a Resource name, and don't permit
 
 
 /* sql.c */
 B_DB *db_init_database(JCR *jcr, char *db_name, char *db_user, char *db_password, 
-                       char *db_address, int db_port, char *db_socket);
+                      char *db_address, int db_port, char *db_socket);
 int db_open_database(JCR *jcr, B_DB *db);
 void db_close_database(JCR *jcr, B_DB *db);
 void db_escape_string(char *snew, char *old, int len);
 int db_create_media_record(JCR *jcr, B_DB *db, MEDIA_DBR *media_dbr);
 int db_create_client_record(JCR *jcr, B_DB *db, CLIENT_DBR *cr);
 int db_create_fileset_record(JCR *jcr, B_DB *db, FILESET_DBR *fsr);
-int db_create_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr);          
+int db_create_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr);         
 int db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jr);
 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
 
 int  db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
 int  db_add_SIG_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *SIG, int type);  
 int  db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId);
+void db_make_slot_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
 
 #endif /* __SQL_PROTOS_H */
 
 
 
 /* 
- * Create Unique Media record  
+ * Create Media record. VolumeName and non-zero Slot must be unique
+ *
  * Returns: 0 on failure
  *         1 on success
  */ 
       sql_free_result(mdb);
    }
 
+   /* Make sur Slot, if non-zero, is unique */
+   db_make_slot_unique(jcr, mdb, mr);
+
    /* Must create it */
    if (mr->LabelDate) {
       localtime_r(&mr->LabelDate, &tm); 
 
       }
       localtime_r(&ttime, &tm);
       strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
-      Mmsg(&mdb->cmd, "UPDATE Media SET LabelDate='%s'\
- WHERE VolumeName='%s'", dt, mr->VolumeName);
+      Mmsg(&mdb->cmd, "UPDATE Media SET LabelDate='%s' "
+           "WHERE VolumeName='%s'", dt, mr->VolumeName);
       stat = UPDATE_DB(jcr, mdb, mdb->cmd);
    }
+   
+   /* Make sure Slot, if non-zero, is unique */
+   db_make_slot_unique(jcr, mdb, mr);
 
    ttime = mr->LastWritten;
    localtime_r(&ttime, &tm);
    return stat;
 }
 
+/* 
+ * If we have a non-zero Slot, ensure that no other Media
+ *  record in this Pool has the same Slot by setting Slot=0.
+ *
+ * This routine assumes the database is already locked.
+ */
+void
+db_make_slot_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) 
+{
+   if (mr->Slot != 0) {
+      Mmsg(&mdb->cmd, "UPDATE Media SET Slot=0 WHERE PoolId=%u "
+           "AND Slot=%d\n", mr->PoolId, mr->Slot);
+      Dmsg1(400, "%s\n", mdb->cmd);
+      UPDATE_DB(jcr, mdb, mdb->cmd);
+   }
+}
+
 #endif /* HAVE_MYSQL || HAVE_SQLITE */
 
         p = (char *)ie->name_list.get(j);
         switch (*p) {
          case '|':
+           p++;                      /* skip over the | */
             fd->msg = edit_job_codes(jcr, fd->msg, p, "");
             bpipe = open_bpipe(fd->msg, 0, "r");
            if (!bpipe) {
 
  */
 int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create)
 {
-   int ok, retry = 0;
+   int retry = 0;
+   bool ok;
 
    mr->PoolId = jcr->PoolId;
    bstrncpy(mr->MediaType, jcr->store->media_type, sizeof(mr->MediaType));
    db_lock(jcr->db);
    for ( ;; ) {
       bstrncpy(mr->VolStatus, "Append", sizeof(mr->VolStatus));  /* want only appendable volumes */
+      /*
+       *  1. Look for volume with "Append" status.
+       */
       ok = db_find_next_volume(jcr, jcr->db, 1, mr);  
       Dmsg2(100, "catreq after find_next_vol ok=%d FW=%d\n", ok, mr->FirstWritten);
       if (!ok) {
-        /* Well, try finding recycled volumes */
+        /*
+         * 2. Try finding a recycled volume
+         */
         ok = find_recycled_volume(jcr, mr);
          Dmsg2(100, "find_recycled_volume %d FW=%d\n", ok, mr->FirstWritten);
         if (!ok) {
+           /*
+            * 3. Try pruning Volumes
+            */
            prune_volumes(jcr);  
            ok = recycle_oldest_purged_volume(jcr, mr);
             Dmsg2(200, "find_recycled_volume2 %d FW=%d\n", ok, mr->FirstWritten);
            if (!ok && create) {
-              /* See if we can create a new Volume */
+              /*
+                * 4. Try "creating" a new Volume
+               */
               ok = newVolume(jcr, mr);
            }
         }
 
+        /* 
+         *  Look at more drastic ways to find an Appendable Volume
+         */ 
         if (!ok && (jcr->pool->purge_oldest_volume ||
                     jcr->pool->recycle_oldest_volume)) {
             Dmsg2(200, "No next volume found. PurgeOldest=%d\n RecyleOldest=%d",
            if (ok) {
               UAContext *ua;
                Dmsg0(400, "Try purge.\n");
-              /* Try to purge oldest volume */
+              /* 
+               * 5.  Try to purging oldest volume only if not UA calling us.
+               */
               ua = new_ua_context(jcr);
-              if (jcr->pool->purge_oldest_volume) {
+              if (jcr->pool->purge_oldest_volume && create) {
                   Jmsg(jcr, M_INFO, 0, _("Purging oldest volume \"%s\"\n"), mr->VolumeName);
                  ok = purge_jobs_from_volume(ua, mr);
-              } else {
+              /*
+               * 5. or try recycling the oldest volume
+               */
+              } else if (jcr->pool->recycle_oldest_volume) {
                   Jmsg(jcr, M_INFO, 0, _("Pruning oldest volume \"%s\"\n"), mr->VolumeName);
                  ok = prune_volume(ua, mr);
               }
 
 static void update_volpool(UAContext *ua, char *val, MEDIA_DBR *mr)
 {
    POOL_DBR pr;
-   POOLMEM *query;
+
    memset(&pr, 0, sizeof(pr));
    bstrncpy(pr.Name, val, sizeof(pr.Name));
    if (!get_pool_dbr(ua, &pr)) {
       return;
    }
-   query = get_pool_memory(PM_MESSAGE);
-   Mmsg(&query, "UPDATE Media SET PoolId=%u WHERE MediaId=%u", pr.PoolId, mr->MediaId);
-   if (!db_sql_query(ua->db, query, NULL, NULL)) {  
-      bsendmsg(ua, "%s", db_strerror(ua->db));
-   } else {      
+   mr->PoolId = pr.PoolId;           /* set new PoolId */
+   /*
+    * Make sure to use db_update... rather than doing this directly,
+    *  so that any Slot is handled correctly. 
+    */
+   if (!db_update_media_record(ua->jcr, ua->db, mr)) {
+      bsendmsg(ua, _("Error updating media record Pool: ERR=%s"), db_strerror(ua->db));
+   } else {
       bsendmsg(ua, _("New Pool is: %s\n"), pr.Name);
    }
-   free_pool_memory(query);
 }
 
 /*
               pr.MaxVols);
            break;
         }
-        query = get_pool_memory(PM_MESSAGE);
-         Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%u",
-           slot, mr.MediaId);
-        if (!db_sql_query(ua->db, query, NULL, NULL)) {  
-            bsendmsg(ua, "%s", db_strerror(ua->db));
+        mr.Slot = slot;
+        /*
+         * Make sure to use db_update... rather than doing this directly,
+         *   so that any Slot is handled correctly. 
+         */
+        if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+            bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
         } else {
-            bsendmsg(ua, "New Slot is: %d\n", slot);
+            bsendmsg(ua, _("New Slot is: %s\n"), mr.Slot);
         }
-        free_pool_memory(query);
         break;
 
       case 8:                        /* Volume Files */
 {
    if (ua->db) {
       db_close_database(ua->jcr, ua->db);
+      ua->db = NULL;
+      if (ua->jcr) {
+        ua->jcr->db = NULL;
+      }
    }
-   ua->db = NULL;
 }
 
 
    switch (*p) {
    case '|':
+      p++;                           /* skip over | */
       fn = get_pool_memory(PM_FNAME);
       fn = edit_job_codes(jcr, fn, p, "");
       bpipe = open_bpipe(fn, 0, "r");
 
 {
 #ifndef HAVE_CYGWIN
    int i;
-   int cpid;
+   pid_t cpid;
    mode_t oldmask;
    /*
     *  Become a daemon.
 
 #undef  VERSION
 #define VERSION "1.33"
 #define VSTRING "1"
-#define BDATE   "06 Nov 2003"
-#define LSMDATE "06Nov03"
+#define BDATE   "09 Nov 2003"
+#define LSMDATE "09Nov03"
 
 /* Debug flags */
 #undef  DEBUG