示例#1
0
文件: dvd.c 项目: anarexia/bacula
void dvd_remove_empty_part(DCR *dcr) 
{
   DEVICE *dev = dcr->dev;

   /* Remove the last part file if it is empty */
   if (dev->is_dvd() && dev->num_dvd_parts > 0) {
      struct stat statp;
      uint32_t part_save = dev->part;
      POOL_MEM archive_name(PM_FNAME);
      int status;

      dev->part = dev->num_dvd_parts;
      make_spooled_dvd_filename(dev, archive_name);
      /* Check that the part file is empty */
      status = stat(archive_name.c_str(), &statp);
      if (status == 0 && statp.st_size == 0) {
         Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n", 
                part_save, dev->num_dvd_parts, dev->getVolCatName());
         Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
         unlink(archive_name.c_str());
         if (part_save == dev->part) {
            dev->set_part_spooled(false);  /* no spooled part left */
         }
      } else if (status < 0) {                         
         if (part_save == dev->part) {
            dev->set_part_spooled(false);  /* spool doesn't exit */
         }
      }       
      dev->part = part_save;               /* restore part number */
   }
}
示例#2
0
/*
 * Wait for a specific device to be released
 *  We wait a maximum of 1 minute then
 *  retry just in case a broadcast was lost.
 *
 * Returns: true  if the device has changed state
 *          false if the total wait time has expired.
 */
bool wait_for_device(DCR *dcr, int &retries)
{
   struct timeval tv;
   struct timezone tz;
   struct timespec timeout;
   JCR *jcr = dcr->jcr;
   DEVICE *dev = dcr->dev;
   int stat = 0;
   bool ok = true;
   const int max_wait_time = 1 * 60;       /* wait 1 minute */
   char ed1[50];

   Dmsg3(40, "Enter wait_for_device. busy=%d dcrvol=%s devvol=%s\n",
      dev->is_busy(), dcr->VolumeName, dev->getVolCatName());

   P(device_release_mutex);

   if (++retries % 5 == 0) {
      /* Print message every 5 minutes */
      Jmsg(jcr, M_MOUNT, 0, _("JobId=%s, Job %s waiting device %s.\n"),
         edit_uint64(jcr->JobId, ed1), jcr->Job, dcr->dev->print_name());
   }

   gettimeofday(&tv, &tz);
   timeout.tv_nsec = tv.tv_usec * 1000;
   timeout.tv_sec = tv.tv_sec + max_wait_time;

   Dmsg0(dbglvl, "Going to wait for a device.\n");

   /* Wait required time */
   stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
   Dmsg1(dbglvl, "Wokeup from sleep on device stat=%d\n", stat);

   V(device_release_mutex);
   Dmsg1(dbglvl, "Return from wait_device ok=%d\n", ok);
   return ok;
}
示例#3
0
文件: dvd.c 项目: anarexia/bacula
/*
 * Open the first part file.
 *  - Close the fd
 *  - Reopen the device
 */
static bool dvd_open_first_part(DCR *dcr, int mode)
{
   DEVICE *dev = dcr->dev;

   Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(), 
         dev->getVolCatName(), dev->openmode, dev->num_dvd_parts, dev->can_append());


   dev->close_part(dcr);

   Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), 
         mode);
   Dmsg0(100, "Set part=1\n");
   dev->part = 1;
   dev->part_start = 0;

   if (dev->open(dcr, mode) < 0) {
      Dmsg0(400, "open dev() failed\n");
      return false;
   }
   Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
   
   return true;
}
示例#4
0
文件: acquire.c 项目: yunnet/bareos
/*
 * This job is done, so release the device. From a Unix standpoint,
 *  the device remains open.
 *
 * Note, if we were spooling, we may enter with the device blocked.
 *   We unblock at the end, only if it was us who blocked the
 *   device.
 *
 */
bool release_device(DCR *dcr)
{
   utime_t now;
   JCR *jcr = dcr->jcr;
   DEVICE *dev = dcr->dev;
   bool ok = true;
   char tbuf[100];
   int was_blocked = BST_NOT_BLOCKED;

   /*
    * Capture job statistics now that we are done using this device.
    */
   now = (utime_t)time(NULL);
   update_job_statistics(jcr, now);

   dev->Lock();
   if (!dev->is_blocked()) {
      block_device(dev, BST_RELEASING);
   } else {
      was_blocked = dev->blocked();
      dev->set_blocked(BST_RELEASING);
   }
   lock_volumes();
   Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape() ? "tape" : "disk");

   /*
    * If device is reserved, job never started, so release the reserve here
    */
   dcr->clear_reserved();

   if (dev->can_read()) {
      VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
      dev->clear_read();              /* clear read bit */
      Dmsg2(150, "dir_update_vol_info. label=%d Vol=%s\n",
         dev->is_labeled(), vol->VolCatName);
      if (dev->is_labeled() && vol->VolCatName[0] != 0) {
         dcr->dir_update_volume_info(false, false); /* send Volume info to Director */
         remove_read_volume(jcr, dcr->VolumeName);
         volume_unused(dcr);
      }
   } else if (dev->num_writers > 0) {
      /*
       * Note if WEOT is set, we are at the end of the tape and may not be positioned correctly,
       * so the job_media_record and update_vol_info have already been done,
       * which means we skip them here.
       */
      dev->num_writers--;
      Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
      if (dev->is_labeled()) {
         Dmsg2(200, "dir_create_jobmedia. Release vol=%s dev=%s\n",
               dev->getVolCatName(), dev->print_name());
         if (!dev->at_weot() && !dcr->dir_create_jobmedia_record(false)) {
            Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
               dcr->getVolCatName(), jcr->Job);
         }

         /*
          * If no more writers, and no errors, and wrote something, write an EOF
          */
         if (!dev->num_writers && dev->can_write() && dev->block_num > 0) {
            dev->weof(1);
            write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
         }
         if (!dev->at_weot()) {
            dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */

            /*
             * Note! do volume update before close, which zaps VolCatInfo
             */
            dcr->dir_update_volume_info(false, false); /* send Volume info to Director */
            Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n",
                  dev->getVolCatName(), dev->print_name());
         }
         if (dev->num_writers == 0) {         /* if not being used */
            volume_unused(dcr);               /*  we obviously are not using the volume */
         }
      }

   } else {
      /*
       * If we reach here, it is most likely because the job has failed,
       * since the device is not in read mode and there are no writers.
       * It was probably reserved.
       */
      volume_unused(dcr);
   }

   Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(), dev->print_name());

   /*
    * If no writers, close if file or !CAP_ALWAYS_OPEN
    */
   if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
      dev->close(dcr);
      free_volume(dev);
   }

   unlock_volumes();

   /*
    * Fire off Alert command and include any output
    */
   if (!job_canceled(jcr)) {
      if (!dcr->device->drive_tapealert_enabled && dcr->device->alert_command) {
         int status = 1;
         POOLMEM *alert, *line;
         BPIPE *bpipe;

         alert = get_pool_memory(PM_FNAME);
         line = get_pool_memory(PM_FNAME);

         alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");

         /*
          * Wait maximum 5 minutes
          */
         bpipe = open_bpipe(alert, 60 * 5, "r");
         if (bpipe) {
            while (bfgets(line, bpipe->rfd)) {
               Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
            }
            status = close_bpipe(bpipe);
         } else {
            status = errno;
         }
         if (status != 0) {
            berrno be;
            Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"), alert, be.bstrerror(status));
         }

         Dmsg1(400, "alert status=%d\n", status);
         free_pool_memory(alert);
         free_pool_memory(line);
      } else {
         /*
          * If all reservations are cleared for this device raise an event that SD plugins can register to.
          */
         if (dev->num_reserved() == 0) {
            generate_plugin_event(jcr, bsdEventDeviceReleased, dcr);
         }
      }
   }

   pthread_cond_broadcast(&dev->wait_next_vol);
   Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n",
         (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
   release_device_cond();

   /*
    * If we are the thread that blocked the device, then unblock it
    */
   if (pthread_equal(dev->no_wait_id, pthread_self())) {
      dev->dunblock(true);
   } else {
      /*
       * Otherwise, reset the prior block status and unlock
       */
      dev->set_blocked(was_blocked);
      dev->Unlock();
   }

   if (dcr->keep_dcr) {
      detach_dcr_from_dev(dcr);
   } else {
      free_dcr(dcr);
   }

   Dmsg2(100, "Device %s released by JobId=%u\n", dev->print_name(), (uint32_t)jcr->JobId);

   return ok;
}
示例#5
0
文件: dvd.c 项目: anarexia/bacula
/*
 * Checks if we can write on a non-blank DVD: meaning that it just have been
 * truncated (there is only one zero-sized file on the DVD).
 *  
 * Note!  Normally if we can mount the device, which should be the case
 *   when we get here, it is not a blank DVD.  Hence we check if
 *   if all files are of zero length (i.e. no data), in which case we allow it.
 *
 */
bool check_can_write_on_non_blank_dvd(DCR *dcr) 
{
   DEVICE* dev = dcr->dev;
   DIR* dp;
   struct dirent *entry, *result;
   int name_max;
   struct stat filestat;
   bool ok = true;
      
   name_max = pathconf(".", _PC_NAME_MAX);
   if (name_max < 1024) {
      name_max = 1024;
   }
   
   if (!(dp = opendir(dev->device->mount_point))) {
      berrno be;
      dev->dev_errno = errno;
      Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
            dev->device->mount_point, dev->print_name(), be.bstrerror());
      return false;
   }
   
   entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
   for ( ;; ) {
      if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
         dev->dev_errno = EIO;
         Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n", 
               dev->device->mount_point, dev->print_name());
         break;
      } else {
         Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n", 
               result->d_name, dev->getVolCatName());
         if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
             strcmp(result->d_name, ".keep")) {
            /* Found a file, checking it is empty */
            POOL_MEM filename(PM_FNAME);
            pm_strcpy(filename, dev->device->mount_point);
            if (!IsPathSeparator(filename.c_str()[strlen(filename.c_str())-1])) {
               pm_strcat(filename, "/");
            }
            pm_strcat(filename, result->d_name);
            if (stat(filename.c_str(), &filestat) < 0) {
               berrno be;
               dev->dev_errno = errno;
               Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n", 
                  filename.c_str(), be.bstrerror());
               ok = false;
               break;
            }
            Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n", 
               filename.c_str(), filestat.st_size);
            if (filestat.st_size != 0) {
               ok = false;
               break;
            }
         }
      }
   }
   free(entry);
   closedir(dp);
   
   Dmsg1(29, "OK  can_write_on_non_blank_dvd: OK=%d\n", ok);
   return ok;
}
示例#6
0
文件: dvd.c 项目: anarexia/bacula
/*
 * Open the next part file.
 *  - Close the fd
 *  - Increment part number 
 *  - Reopen the device
 */
int dvd_open_next_part(DCR *dcr)
{
   DEVICE *dev = dcr->dev;

   Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
      dev->part, dev->num_dvd_parts, dev->print_name(),
         dev->getVolCatName(), dev->openmode, dev->file_addr);
   if (!dev->is_dvd()) {
      Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name()); 
      return -1;
   }
   
   /* When appending, do not open a new part if the current is empty */
   if (dev->can_append() && (dev->part > dev->num_dvd_parts) && 
       (dev->part_size == 0)) {
      Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
      return dev->fd();
   }

   dev->close_part(dcr);               /* close current part */
   
   /*
    * If we have a spooled part open, write it to the
    *  DVD before opening the next part.
    */
   if (dev->is_part_spooled()) {
      Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
         dev->part, dev->num_dvd_parts);
      if (!dvd_write_part(dcr)) {
         Dmsg0(29, "Error in dvd_write part.\n");
         return -1;
      }
   }
     
   dev->part_start += dev->part_size;
   dev->part++;
   Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);

   /* Are we working on a part past what is written in the DVD? */
   if (dev->num_dvd_parts < dev->part) {
      POOL_MEM archive_name(PM_FNAME);
      struct stat buf;
      /* 
       * First check what is on DVD.  If our part is there, we
       *   are in trouble, so bail out.
       * NB: This is however not a problem if we are writing the first part.
       * It simply means that we are over writing an existing volume...
       */
      if (dev->num_dvd_parts > 0) {
         make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
         Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
         if (stat(archive_name.c_str(), &buf) == 0) {
            /* bad news bail out */
            dev->set_part_spooled(false);
            Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
               archive_name.c_str());
            return -1;
         }
      }

#ifdef neeeded
      Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
      make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
      
      /* Check if the next part exists in spool directory . */
      Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
      if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
         Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
         /* Then try to unlink it */
         if (unlink(archive_name.c_str()) < 0) {
            berrno be;
            dev->set_part_spooled(false);
            dev->dev_errno = errno;
            Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
                   archive_name.c_str(), be.bstrerror());
            return -1;
         }
      }
#endif
   }

   Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), 
         dev->openmode);

   /* Open next part.  Note, this sets part_size for part opened. */
   if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
      return -1;
   } 
   dev->set_labeled();                   /* all next parts are "labeled" */
   
   return dev->fd();
}