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 routine does not update the part number, so normally, you
290 * should call open_next_part()
291 * It is also called from truncate_dvd_dev to "blank" the medium, as
292 * well as from block.c when the DVD is full to write the last part.
294 bool dvd_write_part(DCR *dcr)
296 DEVICE *dev = dcr->dev;
297 POOL_MEM ocmd(PM_FNAME);
303 sm_check(__FILE__, __LINE__, false);
304 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
305 icmd = dev->device->write_part_command;
307 edit_device_codes_dev(dev, ocmd, icmd);
310 * Wait at most the time a maximum size part is written in DVD 0.5x speed
311 * FIXME: Minimum speed should be in device configuration
313 timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
315 Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
318 POOL_MEM results(PM_MESSAGE);
319 sm_check(__FILE__, __LINE__, false);
320 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
321 sm_check(__FILE__, __LINE__, false);
323 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
325 Dmsg1(000, "%s", dev->errmsg);
326 dev->dev_errno = EIO;
327 mark_volume_in_error(dcr);
330 sm_check(__FILE__, __LINE__, false);
334 POOL_MEM archive_name(PM_FNAME);
335 /* Delete spool file */
336 make_spooled_dvd_filename(dev, archive_name);
337 unlink(archive_name.c_str());
338 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
339 sm_check(__FILE__, __LINE__, false);
342 /* growisofs umounted the device, so remount it (it will update the free space) */
343 dev->clear_mounted();
345 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
346 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
347 sm_check(__FILE__, __LINE__, false);
351 /* Open the next part file.
353 * - Increment part number
354 * - Reopen the device
356 int dvd_open_next_part(DCR *dcr)
358 DEVICE *dev = dcr->dev;
360 Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
361 dev->part, dev->num_parts, dev->print_name(),
362 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
363 if (!dev->is_dvd()) {
364 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
368 /* When appending, do not open a new part if the current is empty */
369 if (dev->can_append() && (dev->part >= dev->num_parts) &&
370 (dev->part_size == 0)) {
371 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
383 * If we have a part open for write, then write it to
384 * DVD before opening the next part.
386 if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
387 if (!dvd_write_part(dcr)) {
392 if (dev->part > dev->num_parts) {
393 Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
394 ASSERT(dev->part <= dev->num_parts);
396 dev->part_start += dev->part_size;
399 Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
400 /* I think this dev->can_append() should not be there */
401 if ((dev->num_parts < dev->part) && dev->can_append()) {
402 POOL_MEM archive_name(PM_FNAME);
405 * First check what is on DVD. If our part is there, we
406 * are in trouble, so bail out.
407 * NB: This is however not a problem if we are writing the first part.
408 * It simply means that we are overriding an existing volume...
410 if (dev->num_parts > 0) {
411 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
412 if (stat(archive_name.c_str(), &buf) == 0) {
413 /* bad news bail out */
414 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
415 archive_name.c_str());
420 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
421 dev->num_parts = dev->part;
422 dev->VolCatInfo.VolCatParts = dev->part;
423 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
425 /* Check if the next part exists in spool directory . */
426 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
427 Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
428 /* Then try to unlink it */
429 if (unlink(archive_name.c_str()) < 0) {
431 dev->dev_errno = errno;
432 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
433 archive_name.c_str(), be.strerror());
438 if (dev->num_parts < dev->part) {
439 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
440 dev->num_parts = dev->part;
441 dev->VolCatInfo.VolCatParts = dev->part;
443 Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName,
447 int append = dev->can_append();
448 if (dev->open(dcr, dev->openmode) < 0) {
451 dev->set_labeled(); /* all next parts are "labeled" */
452 if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
459 /* Open the first part file.
461 * - Reopen the device
463 int dvd_open_first_part(DCR *dcr, int mode)
465 DEVICE *dev = dcr->dev;
467 Dmsg4(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d\n", dev->print_name(),
468 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts);
479 Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
481 if (dev->open(dcr, mode) < 0) {
482 Dmsg0(50, "open dev() failed\n");
485 Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
490 /* Protected version of lseek, which opens the right part if necessary */
491 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
496 Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
497 dev->part, dev->num_parts);
498 if (!dev->is_dvd()) {
499 Dmsg0(100, "Using sys lseek\n");
500 return lseek(dev->fd, offset, whence);
503 dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
506 Dmsg2(100, "lseek_dev SEEK_SET to %d (part_start=%d)\n", (int)offset, (int)dev->part_start);
507 if ((uint64_t)offset >= dev->part_start) {
508 if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
509 /* We are staying in the current part, just seek */
510 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
513 return pos + dev->part_start;
516 /* Load next part, and start again */
517 if (dvd_open_next_part(dcr) < 0) {
518 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
521 return lseek_dev(dev, offset, SEEK_SET);
525 * pos < dev->part_start :
526 * We need to access a previous part,
527 * so just load the first one, and seek again
528 * until the right one is loaded
530 if (dvd_open_first_part(dcr, dev->openmode) < 0) {
531 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
534 return lseek_dev(dev, offset, SEEK_SET);
538 Dmsg1(100, "lseek_dev SEEK_CUR to %d\n", (int)offset);
539 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
542 pos += dev->part_start;
544 Dmsg1(100, "lseek_dev SEEK_CUR returns %d\n", pos);
546 } else { /* Not used in Bacula, but should work */
547 return lseek_dev(dev, pos, SEEK_SET);
551 Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset);
553 * Bacula does not use offsets for SEEK_END
554 * Also, Bacula uses seek_end only when it wants to
555 * append to the volume, so for a dvd that means
556 * that the volume must be spooled since the DVD
557 * itself is read-only (as currently implemented).
559 if (offset > 0) { /* Not used by bacula */
560 Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset);
564 /* If we are already on a spooled part and have the
565 * right part number, simply seek
567 if (dev->is_part_spooled() && dev->part == dev->num_parts) {
568 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
571 Dmsg1(100, "lseek_dev SEEK_END returns %d\n", pos + dev->part_start);
572 return pos + dev->part_start;
576 * Load the first part, then load the next until we reach the last one.
577 * This is the only way to be sure we compute the right file address.
579 * Save previous openmode, and open all but last part read-only
582 int modesave = dev->openmode;
583 /* Works because num_parts > 0. */
584 if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
585 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
588 if (dev->num_parts > 0) {
589 while (dev->part < (dev->num_parts-1)) {
590 if (dvd_open_next_part(dcr) < 0) {
591 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
595 dev->openmode = modesave;
596 if (dvd_open_next_part(dcr) < 0) {
597 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
601 return lseek_dev(dev, 0, SEEK_END);
610 bool dvd_close_job(DCR *dcr)
612 DEVICE *dev = dcr->dev;
616 /* If the device is a dvd and WritePartAfterJob
617 * is set to yes, open the next part, so, in case of a device
618 * that requires mount, it will be written to the device.
620 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
621 Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
623 if (dev->part < dev->num_parts) {
624 Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
625 dev->part, dev->num_parts, dev->print_name());
626 dev->dev_errno = EIO;
630 /* This should be !dvd_write_part(dcr)
631 NB: No! If you call dvd_write_part, the part number is not updated.
632 You must open the next part, it will automatically write the part and
633 update the part number. */
634 if (ok && (dvd_open_next_part(dcr) < 0)) {
635 Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
636 dev->print_name(), strerror_dev(dev));
637 dev->dev_errno = EIO;
641 Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
642 dev->VolCatInfo.VolCatParts = dev->num_parts;
646 bool truncate_dvd_dev(DCR *dcr) {
647 DEVICE* dev = dcr->dev;
649 /* Set num_parts to zero (on disk) */
651 dcr->VolCatInfo.VolCatParts = 0;
652 dev->VolCatInfo.VolCatParts = 0;
654 Dmsg0(100, "truncate_dvd_dev: Opening first part (1)...\n");
656 dev->truncating = true;
657 if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
658 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (1).\n");
659 dev->truncating = false;
662 dev->truncating = false;
664 Dmsg0(100, "truncate_dvd_dev: Truncating...\n");
666 /* If necessary, truncate it. */
667 if (ftruncate(dev->fd, 0) != 0) {
669 Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
670 dev->print_name(), be.strerror());
678 Dmsg0(100, "truncate_dvd_dev: Opening first part (2)...\n");
680 if (!dvd_write_part(dcr)) {
681 Dmsg0(100, "truncate_dvd_dev: Error while writing to DVD.\n");
685 if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
686 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
693 /* Checks if we can write on a non-blank DVD: meaning that it just have been
694 * truncated (there is only one zero-sized file on the DVD, with the right
696 bool check_can_write_on_non_blank_dvd(DCR *dcr) {
697 DEVICE* dev = dcr->dev;
699 struct dirent *entry, *result;
702 int matched = 0; /* We found an empty file with the right name. */
703 struct stat filestat;
705 name_max = pathconf(".", _PC_NAME_MAX);
706 if (name_max < 1024) {
710 if (!(dp = opendir(dev->device->mount_point))) {
712 dev->dev_errno = errno;
713 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
714 dev->device->mount_point, dev->print_name(), be.strerror());
718 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
720 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
721 dev->dev_errno = EIO;
722 Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n",
723 dev->device->mount_point, dev->print_name());
727 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
728 result->d_name, dev->VolCatInfo.VolCatName);
729 if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
730 /* Found the file, checking it is empty */
731 POOL_MEM filename(PM_FNAME);
732 pm_strcpy(filename, dev->device->mount_point);
733 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
734 pm_strcat(filename, "/");
736 pm_strcat(filename, dev->VolCatInfo.VolCatName);
737 if (stat(filename.c_str(), &filestat) < 0) {
739 dev->dev_errno = errno;
740 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
741 filename.c_str(), be.strerror());
744 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n",
745 filename.c_str(), filestat.st_size);
746 matched = (filestat.st_size == 0);
754 Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
757 /* There is more than 3 files (., .., and the volume file) */
765 * Edit codes into (Un)MountCommand, Write(First)PartCommand
767 * %a = archive device name
768 * %e = erase (set if cannot mount and first part)
770 * %v = last part name
772 * omsg = edited output message
773 * imsg = input string containing edit codes (%x)
776 static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
782 POOL_MEM archive_name(PM_FNAME);
785 Dmsg1(800, "edit_device_codes: %s\n", imsg);
786 for (p=imsg; *p; p++) {
796 if (dev->part == 0) {
803 bsnprintf(add, sizeof(add), "%d", dev->part);
807 str = dev->device->mount_point;
810 make_spooled_dvd_filename(dev, archive_name);
811 str = archive_name.c_str();
825 Dmsg1(1900, "add_str %s\n", str);
826 pm_strcat(omsg, (char *)str);
827 Dmsg1(1800, "omsg=%s\n", omsg.c_str());