elif test -f /etc/engarde-version
 then
         DISTNAME=engarde
-elif test "$ac_cv_cygwin" = yes
+elif test "$CYGWIN" = yes
 then
         DISTNAME=cygwin
         AC_DEFINE(HAVE_CYGWIN)
      ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
   fi
 ])
-
 
 elif test -f /etc/engarde-version
 then
         DISTNAME=engarde
-elif test "$ac_cv_cygwin" = yes
+elif test "$CYGWIN" = yes
 then
         DISTNAME=cygwin
         cat >>confdefs.h <<\_ACEOF
 
 - Add counter variable test.
                 
 For 1.32:
-- Look at Cleaning tape in ua_label.c for media create/update 
-- Fix get_storage_from_media_type (ua_restore) to use command line     
-  storage=
-- Document list nextvol and status output.
 - Add GUI interface to manual
-- Add regression testing to the manual
-
+- Document that Volume pruning can delete last Full backup and
+  hence you will not have a valid backup.
+- Clarify the fact that having the Bacula cygwin1.dll loaded
+  is not the same as having cygwin installed.
+- Fix sparse file handeling so that it always reads a multiple
+  of 512. Currently, it subtracts 8 bytes (for faddr).
+- Separate Dir heartbeat in FD from the SD heartbeat.
 
 For 1.33
+- When job rescheduled, status gives is waiting for Client Rufus 
+  to connect to Storage File. Dir needs to inform SD that job
+  is rescheduled.
+- Fix get_storage_from_media_type (ua_restore) to use command line     
+  storage=
 - Enhance "update slots" to include a "scan" feature
   scan 1; scan 1-5; scan 1,2,4 ...  to update the catalog 
 - Allow a slot or range of slots on the label barcodes command.
 - Figure out some way to ignore or get past checksum errors in
   reading.
 - The SD spooling file gets created even if it is not used.
+- Look at Cleaning tape in ua_label.c for media create/update 
+- Add regression testing to the manual
+- End time: in job output of rescheduled job is time of first run.
+- Document list nextvol and status output.
 
   FDPort = @fd_port@
   Catalog = MyCatalog
   Password = "@fd_password@"          # password for FileDaemon
-  File Retention = 30d                # 30 days
-  Job Retention = 180d                # six months
+  File Retention = 30 days            # 30 days
+  Job Retention = 6 months            # six months
   AutoPrune = yes                     # Prune expired Jobs/Files
 }
 
   Pool Type = Backup
   Recycle = yes                       # Bacula can automatically recycle Volumes
   AutoPrune = yes                     # Prune expired volumes
-  Volume Retention = 365d             # one year
+  Volume Retention = 365 days         # one year
   Accept Any Volume = yes             # write on any volume in the pool
 }
 
    set_jcr_job_status(jcr, JS_Created);
    jcr->jr.SchedTime = jcr->sched_time;
    jcr->jr.StartTime = jcr->start_time;
+   jcr->jr.EndTime = 0;              /* perhaps rescheduled, clear it */
    jcr->jr.Type = jcr->JobType;
    jcr->jr.Level = jcr->JobLevel;
    jcr->jr.JobStatus = jcr->JobStatus;
 
    /* Ensure that at least one server looks at the queue. */
    stat = start_server(jq);
 
-   if (stat == 0) {
-      pthread_mutex_unlock(&jq->mutex);
-   }
+   pthread_mutex_unlock(&jq->mutex);
    Dmsg0(100, "Return jobq_add\n");
    return stat;
 }
    jq->ready_jobs->prepend(item);
    
    stat = start_server(jq);
-   if (stat != 0) {
-      return stat;
-   }
+
    pthread_mutex_unlock(&jq->mutex);
    Dmsg0(100, "Return jobq_remove\n");
    return stat;
    if (jq->idle_workers > 0) {
       Dmsg0(100, "Signal worker to wake up\n");
       if ((stat = pthread_cond_signal(&jq->work)) != 0) {
-        pthread_mutex_unlock(&jq->mutex);
         return stat;
       }
    } else if (jq->num_workers < jq->max_workers) {
       /* No idle threads so create a new one */
       set_thread_concurrency(jq->max_workers + 1);
       if ((stat = pthread_create(&id, &jq->attr, jobq_server, (void *)jq)) != 0) {
-        pthread_mutex_unlock(&jq->mutex);
         return stat;
       }
-      jq->num_workers++;
    }
    return stat;
 }
    if ((stat = pthread_mutex_lock(&jq->mutex)) != 0) {
       return NULL;
    }
+   jq->num_workers++;
 
    for (;;) {
       struct timeval tv;
         if (!jq->ready_jobs->empty()) {
             Dmsg0(100, "ready queue not empty start server\n");
            if (start_server(jq) != 0) {
+              jq->num_workers--;
+              pthread_mutex_unlock(&jq->mutex);
               return NULL;
            }
         }
         jq->running_jobs->append(je);
          Dmsg1(100, "Took jobid=%d from ready and appended to run\n", jcr->JobId);
         if ((stat = pthread_mutex_unlock(&jq->mutex)) != 0) {
+           jq->num_workers--;
            return NULL;
         }
          /* Call user's routine here */
         jq->engine(je->jcr);
          Dmsg1(100, "Back from user engine jobid=%d.\n", jcr->JobId);
         if ((stat = pthread_mutex_lock(&jq->mutex)) != 0) {
+           jq->num_workers--;
            free(je);                 /* release job entry */
            return NULL;
         }
 
        *  send_label_request() below
        */
       if (is_cleaning_tape(ua, &mr, &pr)) {
-        set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
-        if (db_create_media_record(ua->jcr, ua->db, &mr)) {
-            bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
-              mr.VolumeName);
-        } else {
-            bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
+        if (media_record_exists) {      /* we update it */
+           mr.VolBytes = 1;
+           if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+                bsendmsg(ua, "%s", db_strerror(ua->db));
+           }
+        } else {                        /* create the media record */
+           set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
+           if (db_create_media_record(ua->jcr, ua->db, &mr)) {
+               bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
+                 mr.VolumeName);
+           } else {
+               bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
+           }
         }
-        continue;
+        continue;                    /* done, go handle next volume */
       }
       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
       if (ua->jcr->store_bsock) {
 
         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_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_WaitPriority:
-            msg = _("is waiting for higher priority jobs to finish");
-           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_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_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_WaitPriority:
+         msg = _("is waiting for higher priority jobs to finish");
+        break;
+      case JS_WaitMaxJobs:
+         msg = _("is waiting on max total jobs");
+        break;
+      case JS_WaitStartTime:
+         msg = _("is waiting for its start time");
+        break;
 
 
-        default:
-           msg = (char *) get_pool_memory(PM_FNAME);
-            Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
-           pool_mem = TRUE;
-           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;
-
+      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) {
 
       if (ff_pkt->flags & FO_SPARSE) {
         rbuf += SPARSE_FADDR_SIZE;
         rsize -= SPARSE_FADDR_SIZE;
+#ifdef HAVE_FREEBSD_OS
+        /* 
+         * To read FreeBSD partitions, the read size must be
+         *  a multiple of 512.
+         */
+        rsize = (rsize/512) * 512;
+#endif
       }
 
       /* 
 
    jcr->hb_bsock = sd;
 
    /* Hang reading the socket to the SD, and every time we get
-    *  a heartbeat, we simply send it on to the Director to
-    *  keep him alive.
+    *  a heartbeat or we get a wait timeout (1 minute), we
+    *  check to see if we need to send a heartbeat to the
+    *  Directory.
     */
    for ( ; !is_bnet_stop(sd); ) {
       n = bnet_wait_data_intr(sd, WAIT_INTERVAL);
 
     *  a block device, we do a raw backup of it or if it is
     *  a fifo, we simply read it.
     */
+#ifdef HAVE_FREEBSD_OS
+   /*
+    * On FreeBSD, all block devices are character devices, so
+    *  to be able to read a raw disk, we need the check for
+    *  a character device.
+    * crw-r-----  1 root  operator  - 116, 0x00040002 Jun  9 19:32 /dev/ad0s3
+    * crw-r-----  1 root  operator  - 116, 0x00040002 Jun  9 19:32 /dev/rad0s3
+    */
+   if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
+#else
    if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
+#endif
       ff_pkt->type = FT_RAW;         /* raw partition */
    } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
              ff_pkt->flags & FO_READFIFO) {
 
    struct timeval tv;
    struct timezone tz;
    struct timespec timeout;
+   JCR *ojcr;
 
    /*
     * Get JobId and permissions from Director
       set_jcr_job_status(jcr, JS_ErrorTerminated);
       return 0;
    }
+   /*        
+    * Since this job could be rescheduled, we
+    *  check to see if we have it already. If so
+    *  free the old jcr and use the new one.
+    */
+   ojcr = get_jcr_by_full_name(job);
+   if (ojcr && !ojcr->authenticated) {
+      Dmsg2(000, "Found ojcr=0x%x Job %s\n", (unsigned)ojcr, job);
+      free_jcr(ojcr);
+   }
    jcr->JobId = JobId;
    jcr->VolSessionId = newVolSessionId();
    jcr->VolSessionTime = VolSessionTime;