3 * dvd.c -- Routines specific to DVD devices (and
4 * possibly other removable hard media).
11 Copyright (C) 2005 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 version 2 as amended with additional clauses defined in the
16 file LICENSE in the main source directory.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 the file LICENSE for additional details.
28 /* Forward referenced functions */
29 static void edit_device_codes_dev(DEVICE *dev, POOL_MEM &omsg, const char *imsg);
30 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout);
31 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
34 * Write the current volume/part filename to archive_name.
36 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
38 pm_strcpy(archive_name, dev->device->mount_point);
39 add_file_and_part_name(dev, archive_name);
40 dev->set_part_spooled(false);
43 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
45 /* Use the working directory if spool directory is not defined */
46 if (dev->device->spool_directory) {
47 pm_strcpy(archive_name, dev->device->spool_directory);
49 pm_strcpy(archive_name, working_directory);
51 add_file_and_part_name(dev, archive_name);
52 dev->set_part_spooled(true);
55 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
58 if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
59 pm_strcat(archive_name, "/");
62 pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
63 /* if part > 1, append .# to the filename (where # is the part number) */
65 pm_strcat(archive_name, ".");
66 bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
67 pm_strcat(archive_name, partnumber);
69 Dmsg1(100, "Exit make_dvd_filename: arch=%s\n", archive_name.c_str());
73 * If timeout, wait until the mount command returns 0.
74 * If !timeout, try to mount the device only once.
76 bool mount_dev(DEVICE* dev, int timeout)
78 Dmsg0(90, "Enter mount_dev\n");
79 if (dev->is_mounted()) {
81 } else if (dev->requires_mount()) {
82 return do_mount_dev(dev, 1, timeout);
88 * If timeout, wait until the unmount command returns 0.
89 * If !timeout, try to unmount the device only once.
91 bool unmount_dev(DEVICE *dev, int timeout)
93 Dmsg0(90, "Enter unmount_dev\n");
94 if (dev->is_mounted()) {
95 return do_mount_dev(dev, 0, timeout);
100 /* (Un)mount the device */
101 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout)
103 POOL_MEM ocmd(PM_FNAME);
108 sm_check(__FILE__, __LINE__, false);
110 if (dev->is_mounted()) {
111 Dmsg0(200, "======= DVD mount=1\n");
114 icmd = dev->device->mount_command;
116 if (!dev->is_mounted()) {
117 Dmsg0(200, "======= DVD mount=0\n");
120 icmd = dev->device->unmount_command;
123 edit_device_codes_dev(dev, ocmd, icmd);
125 Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
128 /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
133 results = get_memory(2000);
135 /* If busy retry each second */
136 while ((status = run_program_full_output(ocmd.c_str(),
137 dev->max_open_wait/2, results)) != 0) {
138 /* Doesn't work with internationalisation (This is not a problem) */
139 if (fnmatch("*is already mounted on", results, 0) == 0) {
143 /* Sometimes the device cannot be mounted because it is already mounted.
144 * Try to unmount it, then remount it */
146 Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
147 do_mount_dev(dev, 0, 0);
152 Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
153 Mmsg(dev->errmsg, _("Device %s cannot be mounted. ERR=%s\n"),
154 dev->print_name(), results);
156 * Now, just to be sure it is not mounted, try to read the
160 struct dirent *entry, *result;
164 name_max = pathconf(".", _PC_NAME_MAX);
165 if (name_max < 1024) {
169 if (!(dp = opendir(dev->device->mount_point))) {
171 dev->dev_errno = errno;
172 Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n",
173 dev->device->mount_point, dev->print_name(), be.strerror());
177 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
179 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
180 dev->dev_errno = EIO;
181 Dmsg2(129, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n",
182 dev->device->mount_point, dev->print_name());
190 Dmsg1(29, "open_mounted_dev: got %d files in the mount point\n", count);
193 mount = 1; /* If we got more than . and .. */
194 break; /* there must be something mounted */
197 dev->set_mounted(false);
198 sm_check(__FILE__, __LINE__, false);
199 free_pool_memory(results);
200 Dmsg0(200, "============ DVD mount=0\n");
204 dev->set_mounted(mount); /* set/clear mounted flag */
205 free_pool_memory(results);
206 /* Do not check free space when unmounting (otherwise it will mount it again) */
208 update_free_space_dev(dev);
210 Dmsg1(200, "============ DVD mount=%d\n", mount);
214 /* Update the free space on the device */
215 void update_free_space_dev(DEVICE* dev)
217 POOL_MEM ocmd(PM_FNAME);
224 /* The device must be mounted in order to dvd-freespace to work */
227 sm_check(__FILE__, __LINE__, false);
228 icmd = dev->device->free_space_command;
232 dev->free_space_errno = 0;
234 Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno);
238 edit_device_codes_dev(dev, ocmd, icmd);
240 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
242 results = get_pool_memory(PM_MESSAGE);
244 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
248 if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
249 Dmsg1(100, "Free space program run : %s\n", results);
250 free = str_to_int64(results);
252 dev->free_space = free;
253 dev->free_space_errno = 1;
255 Mmsg0(dev->errmsg, "");
260 dev->free_space_errno = -EPIPE;
261 Mmsg1(dev->errmsg, _("Cannot run free space command (%s)\n"), results);
264 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
265 "free_space_errno=%d ERR=%s\n", dev->print_name(),
266 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
272 dev->dev_errno = -dev->free_space_errno;
273 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
274 "free_space_errno=%d ERR=%s\n",
275 dev->print_name(), edit_uint64(dev->free_space, ed1),
276 dev->free_space_errno, dev->errmsg);
280 free_pool_memory(results);
281 Dmsg3(29, "update_free_space_dev: free_space=%s, free_space_errno=%d have_media=%d\n",
282 edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->have_media());
283 sm_check(__FILE__, __LINE__, false);
288 * Write a part (Vol, Vol.1, ...) from the spool to the DVD
289 * This MUST only be called from open_next_part. Otherwise the part number
291 * It is also called from truncate_dvd_dev to "blank" the medium.
293 static bool dvd_write_part(DCR *dcr)
295 DEVICE *dev = dcr->dev;
296 POOL_MEM ocmd(PM_FNAME);
302 sm_check(__FILE__, __LINE__, false);
303 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
304 icmd = dev->device->write_part_command;
306 edit_device_codes_dev(dev, ocmd, icmd);
309 * Wait at most the time a maximum size part is written in DVD 0.5x speed
310 * FIXME: Minimum speed should be in device configuration
312 timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
314 Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
317 POOL_MEM results(PM_MESSAGE);
318 sm_check(__FILE__, __LINE__, false);
319 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
320 sm_check(__FILE__, __LINE__, false);
322 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
324 Dmsg1(000, "%s", dev->errmsg);
325 dev->dev_errno = EIO;
328 sm_check(__FILE__, __LINE__, false);
332 POOL_MEM archive_name(PM_FNAME);
333 /* Delete spool file */
334 make_spooled_dvd_filename(dev, archive_name);
335 unlink(archive_name.c_str());
336 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
337 sm_check(__FILE__, __LINE__, false);
340 /* growisofs umount the device, so remount it (it will update the free space) */
341 dev->clear_mounted();
343 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
344 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
345 sm_check(__FILE__, __LINE__, false);
349 /* Open the next part file.
351 * - Increment part number
352 * - Reopen the device
354 int open_next_part(DCR *dcr)
356 DEVICE *dev = dcr->dev;
358 Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
359 dev->part, dev->num_parts, dev->print_name(),
360 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
361 if (!dev->is_dvd()) {
362 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
366 /* When appending, do not open a new part if the current is empty */
367 if (dev->can_append() && (dev->part >= dev->num_parts) &&
368 (dev->part_size == 0)) {
369 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
381 * If we have a part open for write, then write it to
382 * DVD before opening the next part.
384 if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
385 if (!dvd_write_part(dcr)) {
390 if (dev->part > dev->num_parts) {
391 Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
392 ASSERT(dev->part <= dev->num_parts);
394 dev->part_start += dev->part_size;
397 Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
398 /* I think this dev->can_append() should not be there */
399 if ((dev->num_parts < dev->part) && dev->can_append()) {
400 POOL_MEM archive_name(PM_FNAME);
403 * First check what is on DVD. If our part is there, we
404 * are in trouble, so bail out.
405 * NB: This is however not a problem if we are writing the first part.
406 * It simply means that we are overriding an existing volume...
408 if (dev->num_parts > 0) {
409 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
410 if (stat(archive_name.c_str(), &buf) == 0) {
411 /* bad news bail out */
412 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
413 archive_name.c_str());
418 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
419 dev->num_parts = dev->part;
420 dev->VolCatInfo.VolCatParts = dev->part;
421 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
423 /* Check if the next part exists in spool directory . */
424 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
425 Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
426 /* Then try to unlink it */
427 if (unlink(archive_name.c_str()) < 0) {
429 dev->dev_errno = errno;
430 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
431 archive_name.c_str(), be.strerror());
436 if (dev->num_parts < dev->part) {
437 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
438 dev->num_parts = dev->part;
439 dev->VolCatInfo.VolCatParts = dev->part;
441 Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName,
445 int append = dev->can_append();
446 if (dev->open(dcr, dev->openmode) < 0) {
449 dev->set_labeled(); /* all next parts are "labeled" */
450 if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
457 /* Open the first part file.
459 * - Reopen the device
461 int open_first_part(DCR *dcr, int mode)
463 DEVICE *dev = dcr->dev;
465 Dmsg4(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d\n", dev->print_name(),
466 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts);
477 Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
479 if (dev->open(dcr, mode) < 0) {
480 Dmsg0(50, "open dev() failed\n");
483 Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
488 /* Protected version of lseek, which opens the right part if necessary */
489 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
494 Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
495 dev->part, dev->num_parts);
496 if (!dev->is_dvd()) {
497 Dmsg0(100, "Using sys lseek\n");
498 return lseek(dev->fd, offset, whence);
501 dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
504 Dmsg2(100, "lseek_dev SEEK_SET to %d (part_start=%d)\n", (int)offset, (int)dev->part_start);
505 if ((uint64_t)offset >= dev->part_start) {
506 if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
507 /* We are staying in the current part, just seek */
508 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
511 return pos + dev->part_start;
514 /* Load next part, and start again */
515 if (open_next_part(dcr) < 0) {
516 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
519 return lseek_dev(dev, offset, SEEK_SET);
523 * pos < dev->part_start :
524 * We need to access a previous part,
525 * so just load the first one, and seek again
526 * until the right one is loaded
528 if (open_first_part(dcr, dev->openmode) < 0) {
529 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
532 return lseek_dev(dev, offset, SEEK_SET);
536 Dmsg1(100, "lseek_dev SEEK_CUR to %d\n", (int)offset);
537 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
540 pos += dev->part_start;
542 Dmsg1(100, "lseek_dev SEEK_CUR returns %d\n", pos);
544 } else { /* Not used in Bacula, but should work */
545 return lseek_dev(dev, pos, SEEK_SET);
549 Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset);
551 * Bacula does not use offsets for SEEK_END
552 * Also, Bacula uses seek_end only when it wants to
553 * append to the volume, so for a dvd that means
554 * that the volume must be spooled since the DVD
555 * itself is read-only (as currently implemented).
557 if (offset > 0) { /* Not used by bacula */
558 Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset);
562 /* If we are already on a spooled part and have the
563 * right part number, simply seek
565 if (dev->is_part_spooled() && dev->part == dev->num_parts) {
566 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
569 Dmsg1(100, "lseek_dev SEEK_END returns %d\n", pos + dev->part_start);
570 return pos + dev->part_start;
574 * Load the first part, then load the next until we reach the last one.
575 * This is the only way to be sure we compute the right file address.
577 * Save previous openmode, and open all but last part read-only
580 int modesave = dev->openmode;
581 /* Works because num_parts > 0. */
582 if (open_first_part(dcr, OPEN_READ_ONLY) < 0) {
583 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
586 if (dev->num_parts > 0) {
587 while (dev->part < (dev->num_parts-1)) {
588 if (open_next_part(dcr) < 0) {
589 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
593 dev->openmode = modesave;
594 if (open_next_part(dcr) < 0) {
595 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
599 return lseek_dev(dev, 0, SEEK_END);
608 bool dvd_close_job(DCR *dcr)
610 DEVICE *dev = dcr->dev;
614 /* If the device is a dvd and WritePartAfterJob
615 * is set to yes, open the next part, so, in case of a device
616 * that requires mount, it will be written to the device.
618 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
619 Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
621 if (dev->part < dev->num_parts) {
622 Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
623 dev->part, dev->num_parts, dev->print_name());
624 dev->dev_errno = EIO;
628 /* This should be !dvd_write_part(dcr)
629 NB: No! If you call dvd_write_part, the part number is not updated.
630 You must open the next part, it will automatically write the part and
631 update the part number. */
632 if (ok && (open_next_part(dcr) < 0)) {
633 // if (ok && !dvd_write_part(dcr)) {
634 Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
635 dev->print_name(), strerror_dev(dev));
636 dev->dev_errno = EIO;
640 Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
641 dev->VolCatInfo.VolCatParts = dev->num_parts;
645 bool truncate_dvd_dev(DCR *dcr) {
646 DEVICE* dev = dcr->dev;
648 /* Set num_parts to zero (on disk) */
650 dcr->VolCatInfo.VolCatParts = 0;
651 dev->VolCatInfo.VolCatParts = 0;
653 Dmsg0(100, "truncate_dvd_dev: Opening first part (1)...\n");
655 dev->truncating = true;
656 if (open_first_part(dcr, OPEN_READ_WRITE) < 0) {
657 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (1).\n");
658 dev->truncating = false;
661 dev->truncating = false;
663 Dmsg0(100, "truncate_dvd_dev: Truncating...\n");
665 /* If necessary, truncate it. */
666 if (ftruncate(dev->fd, 0) != 0) {
668 Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
669 dev->print_name(), be.strerror());
677 Dmsg0(100, "truncate_dvd_dev: Opening first part (2)...\n");
679 if (!dvd_write_part(dcr)) {
680 Dmsg0(100, "truncate_dvd_dev: Error while writing to DVD.\n");
684 if (open_first_part(dcr, OPEN_READ_WRITE) < 0) {
685 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
692 /* Checks if we can write on a non-blank DVD: meaning that it just have been
693 * truncated (there is only one zero-sized file on the DVD, with the right
695 bool check_can_write_on_non_blank_dvd(DCR *dcr) {
696 DEVICE* dev = dcr->dev;
698 struct dirent *entry, *result;
701 int matched = 0; /* We found an empty file with the right name. */
702 struct stat filestat;
704 name_max = pathconf(".", _PC_NAME_MAX);
705 if (name_max < 1024) {
709 if (!(dp = opendir(dev->device->mount_point))) {
711 dev->dev_errno = errno;
712 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
713 dev->device->mount_point, dev->print_name(), be.strerror());
717 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
719 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
720 dev->dev_errno = EIO;
721 Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n",
722 dev->device->mount_point, dev->print_name());
726 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
727 result->d_name, dev->VolCatInfo.VolCatName);
728 if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
729 /* Found the file, checking it is empty */
730 POOL_MEM filename(PM_FNAME);
731 pm_strcpy(filename, dev->device->mount_point);
732 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
733 pm_strcat(filename, "/");
735 pm_strcat(filename, dev->VolCatInfo.VolCatName);
736 if (stat(filename.c_str(), &filestat) < 0) {
738 dev->dev_errno = errno;
739 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
740 filename.c_str(), be.strerror());
743 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n",
744 filename.c_str(), filestat.st_size);
745 matched = (filestat.st_size == 0);
753 Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
756 /* There is more than 3 files (., .., and the volume file) */
764 * Edit codes into (Un)MountCommand, Write(First)PartCommand
766 * %a = archive device name
767 * %e = erase (set if cannot mount and first part)
769 * %v = last part name
771 * omsg = edited output message
772 * imsg = input string containing edit codes (%x)
775 static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
781 POOL_MEM archive_name(PM_FNAME);
784 Dmsg1(800, "edit_device_codes: %s\n", imsg);
785 for (p=imsg; *p; p++) {
795 if (dev->part == 0) {
802 bsnprintf(add, sizeof(add), "%d", dev->part);
806 str = dev->device->mount_point;
809 make_spooled_dvd_filename(dev, archive_name);
810 str = archive_name.c_str();
824 Dmsg1(1900, "add_str %s\n", str);
825 pm_strcat(omsg, (char *)str);
826 Dmsg1(1800, "omsg=%s\n", omsg.c_str());