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 if (fnmatch("*is already mounted on", results, 0) == 0) {
142 /* Sometimes the device cannot be mounted because it is already mounted.
143 * Try to unmount it, then remount it */
145 Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
146 do_mount_dev(dev, 0, 0);
151 Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
152 Mmsg(dev->errmsg, "Device %s cannot be mounted. ERR=%s\n",
153 dev->print_name(), results);
155 * Now, just to be sure it is not mounted, try to read the
159 struct dirent *entry, *result;
163 name_max = pathconf(".", _PC_NAME_MAX);
164 if (name_max < 1024) {
168 if (!(dp = opendir(dev->device->mount_point))) {
170 dev->dev_errno = errno;
171 Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n",
172 dev->device->mount_point, dev->print_name(), be.strerror());
176 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
178 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
179 dev->dev_errno = EIO;
180 Dmsg2(129, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n",
181 dev->device->mount_point, dev->print_name());
189 Dmsg1(29, "open_mounted_dev: got %d files in the mount point\n", count);
192 mount = 1; /* If we got more than . and .. */
193 break; /* there must be something mounted */
196 dev->set_mounted(false);
197 sm_check(__FILE__, __LINE__, false);
198 free_pool_memory(results);
199 Dmsg0(200, "============ DVD mount=0\n");
203 dev->set_mounted(mount); /* set/clear mounted flag */
204 free_pool_memory(results);
205 /* Do not check free space when unmounting (otherwise it will mount it again) */
207 update_free_space_dev(dev);
209 Dmsg1(200, "============ DVD mount=%d\n", mount);
213 /* Update the free space on the device */
214 void update_free_space_dev(DEVICE* dev)
216 POOL_MEM ocmd(PM_FNAME);
223 /* The device must be mounted in order to dvd-freespace to work */
226 sm_check(__FILE__, __LINE__, false);
227 icmd = dev->device->free_space_command;
231 dev->free_space_errno = 0;
233 Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno);
237 edit_device_codes_dev(dev, ocmd, icmd);
239 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
241 results = get_pool_memory(PM_MESSAGE);
243 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
247 if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
248 Dmsg1(100, "Free space program run : %s\n", results);
249 free = str_to_int64(results);
251 dev->free_space = free;
252 dev->free_space_errno = 1;
254 Mmsg0(dev->errmsg, "");
259 dev->free_space_errno = -EPIPE;
260 Mmsg1(dev->errmsg, "Cannot run free space command (%s)\n", results);
263 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
264 "free_space_errno=%d ERR=%s\n", dev->print_name(),
265 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
271 dev->dev_errno = -dev->free_space_errno;
272 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
273 "free_space_errno=%d ERR=%s\n",
274 dev->print_name(), edit_uint64(dev->free_space, ed1),
275 dev->free_space_errno, dev->errmsg);
279 free_pool_memory(results);
280 Dmsg3(29, "update_free_space_dev: free_space=%s, free_space_errno=%d have_media=%d\n",
281 edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->have_media());
282 sm_check(__FILE__, __LINE__, false);
287 * Write a part (Vol, Vol.1, ...) from the spool to the DVD
288 * This MUST only be called from open_next_part. Otherwise the part number
290 * It is also called from truncate_dvd_dev to "blank" the medium.
292 static bool dvd_write_part(DCR *dcr)
294 DEVICE *dev = dcr->dev;
295 POOL_MEM ocmd(PM_FNAME);
301 sm_check(__FILE__, __LINE__, false);
302 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
303 icmd = dev->device->write_part_command;
305 edit_device_codes_dev(dev, ocmd, icmd);
308 * Wait at most the time a maximum size part is written in DVD 0.5x speed
309 * FIXME: Minimum speed should be in device configuration
311 timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
313 Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
316 POOL_MEM results(PM_MESSAGE);
317 sm_check(__FILE__, __LINE__, false);
318 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
319 sm_check(__FILE__, __LINE__, false);
321 Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s",
323 Dmsg1(000, "%s", dev->errmsg);
324 dev->dev_errno = EIO;
327 sm_check(__FILE__, __LINE__, false);
331 POOL_MEM archive_name(PM_FNAME);
332 /* Delete spool file */
333 make_spooled_dvd_filename(dev, archive_name);
334 unlink(archive_name.c_str());
335 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
336 sm_check(__FILE__, __LINE__, false);
339 /* growisofs umount the device, so remount it (it will update the free space) */
340 dev->clear_mounted();
342 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
343 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
344 sm_check(__FILE__, __LINE__, false);
348 /* Open the next part file.
350 * - Increment part number
351 * - Reopen the device
353 int open_next_part(DCR *dcr)
355 DEVICE *dev = dcr->dev;
357 Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
358 dev->part, dev->num_parts, dev->print_name(),
359 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
360 if (!dev->is_dvd()) {
361 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
365 /* When appending, do not open a new part if the current is empty */
366 if (dev->can_append() && (dev->part >= dev->num_parts) &&
367 (dev->part_size == 0)) {
368 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
380 * If we have a part open for write, then write it to
381 * DVD before opening the next part.
383 if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
384 if (!dvd_write_part(dcr)) {
389 if (dev->part > dev->num_parts) {
390 Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
391 ASSERT(dev->part <= dev->num_parts);
393 dev->part_start += dev->part_size;
396 Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
397 /* I think this dev->can_append() should not be there */
398 if ((dev->num_parts < dev->part) && dev->can_append()) {
399 POOL_MEM archive_name(PM_FNAME);
402 * First check what is on DVD. If our part is there, we
403 * are in trouble, so bail out.
404 * NB: This is however not a problem if we are writing the first part.
405 * It simply means that we are overriding an existing volume...
407 if (dev->num_parts > 0) {
408 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
409 if (stat(archive_name.c_str(), &buf) == 0) {
410 /* bad news bail out */
411 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
412 archive_name.c_str());
417 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
418 dev->num_parts = dev->part;
419 dev->VolCatInfo.VolCatParts = dev->part;
420 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
422 /* Check if the next part exists in spool directory . */
423 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
424 Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
425 /* Then try to unlink it */
426 if (unlink(archive_name.c_str()) < 0) {
428 dev->dev_errno = errno;
429 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
430 archive_name.c_str(), be.strerror());
435 if (dev->num_parts < dev->part) {
436 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
437 dev->num_parts = dev->part;
438 dev->VolCatInfo.VolCatParts = dev->part;
440 Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName,
444 int append = dev->can_append();
445 if (dev->open(dcr, dev->openmode) < 0) {
448 dev->set_labeled(); /* all next parts are "labeled" */
449 if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
456 /* Open the first part file.
458 * - Reopen the device
460 int open_first_part(DCR *dcr, int mode)
462 DEVICE *dev = dcr->dev;
464 Dmsg4(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d\n", dev->print_name(),
465 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts);
476 Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
478 if (dev->open(dcr, mode) < 0) {
479 Dmsg0(50, "open dev() failed\n");
482 Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
487 /* Protected version of lseek, which opens the right part if necessary */
488 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
493 Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
494 dev->part, dev->num_parts);
495 if (!dev->is_dvd()) {
496 Dmsg0(100, "Using sys lseek\n");
497 return lseek(dev->fd, offset, whence);
500 dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
503 Dmsg2(100, "lseek_dev SEEK_SET to %d (part_start=%d)\n", (int)offset, (int)dev->part_start);
504 if ((uint64_t)offset >= dev->part_start) {
505 if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
506 /* We are staying in the current part, just seek */
507 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
510 return pos + dev->part_start;
513 /* Load next part, and start again */
514 if (open_next_part(dcr) < 0) {
515 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
518 return lseek_dev(dev, offset, SEEK_SET);
522 * pos < dev->part_start :
523 * We need to access a previous part,
524 * so just load the first one, and seek again
525 * until the right one is loaded
527 if (open_first_part(dcr, dev->openmode) < 0) {
528 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
531 return lseek_dev(dev, offset, SEEK_SET);
535 Dmsg1(100, "lseek_dev SEEK_CUR to %d\n", (int)offset);
536 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
539 pos += dev->part_start;
541 Dmsg1(100, "lseek_dev SEEK_CUR returns %d\n", pos);
543 } else { /* Not used in Bacula, but should work */
544 return lseek_dev(dev, pos, SEEK_SET);
548 Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset);
550 * Bacula does not use offsets for SEEK_END
551 * Also, Bacula uses seek_end only when it wants to
552 * append to the volume, so for a dvd that means
553 * that the volume must be spooled since the DVD
554 * itself is read-only (as currently implemented).
556 if (offset > 0) { /* Not used by bacula */
557 Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset);
561 /* If we are already on a spooled part and have the
562 * right part number, simply seek
564 if (dev->is_part_spooled() && dev->part == dev->num_parts) {
565 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
568 Dmsg1(100, "lseek_dev SEEK_END returns %d\n", pos + dev->part_start);
569 return pos + dev->part_start;
573 * Load the first part, then load the next until we reach the last one.
574 * This is the only way to be sure we compute the right file address.
576 * Save previous openmode, and open all but last part read-only
579 int modesave = dev->openmode;
580 /* Works because num_parts > 0. */
581 if (open_first_part(dcr, OPEN_READ_ONLY) < 0) {
582 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
585 if (dev->num_parts > 0) {
586 while (dev->part < (dev->num_parts-1)) {
587 if (open_next_part(dcr) < 0) {
588 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
592 dev->openmode = modesave;
593 if (open_next_part(dcr) < 0) {
594 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
598 return lseek_dev(dev, 0, SEEK_END);
607 bool dvd_close_job(DCR *dcr)
609 DEVICE *dev = dcr->dev;
613 /* If the device is a dvd and WritePartAfterJob
614 * is set to yes, open the next part, so, in case of a device
615 * that requires mount, it will be written to the device.
617 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
618 Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
620 if (dev->part < dev->num_parts) {
621 Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
622 dev->part, dev->num_parts, dev->print_name());
623 dev->dev_errno = EIO;
627 /* This should be !dvd_write_part(dcr)
628 NB: No! If you call dvd_write_part, the part number is not updated.
629 You must open the next part, it will automatically write the part and
630 update the part number. */
631 if (ok && (open_next_part(dcr) < 0)) {
632 // if (ok && !dvd_write_part(dcr)) {
633 Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
634 dev->print_name(), strerror_dev(dev));
635 dev->dev_errno = EIO;
639 Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
640 dev->VolCatInfo.VolCatParts = dev->num_parts;
644 bool truncate_dvd_dev(DCR *dcr) {
645 DEVICE* dev = dcr->dev;
647 /* Set num_parts to zero (on disk) */
649 dcr->VolCatInfo.VolCatParts = 0;
650 dev->VolCatInfo.VolCatParts = 0;
652 Dmsg0(100, "truncate_dvd_dev: Opening first part (1)...\n");
654 dev->truncating = true;
655 if (open_first_part(dcr, OPEN_READ_WRITE) < 0) {
656 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (1).\n");
657 dev->truncating = false;
660 dev->truncating = false;
662 Dmsg0(100, "truncate_dvd_dev: Truncating...\n");
664 /* If necessary, truncate it. */
665 if (ftruncate(dev->fd, 0) != 0) {
667 Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
668 dev->print_name(), be.strerror());
676 Dmsg0(100, "truncate_dvd_dev: Opening first part (2)...\n");
678 if (!dvd_write_part(dcr)) {
679 Dmsg0(100, "truncate_dvd_dev: Error while writing to DVD.\n");
683 if (open_first_part(dcr, OPEN_READ_WRITE) < 0) {
684 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
691 /* Checks if we can write on a non-blank DVD: meaning that it just have been
692 * truncated (there is only one zero-sized file on the DVD, with the right
694 bool check_can_write_on_non_blank_dvd(DCR *dcr) {
695 DEVICE* dev = dcr->dev;
697 struct dirent *entry, *result;
700 int matched = 0; /* We found an empty file with the right name. */
701 struct stat filestat;
703 name_max = pathconf(".", _PC_NAME_MAX);
704 if (name_max < 1024) {
708 if (!(dp = opendir(dev->device->mount_point))) {
710 dev->dev_errno = errno;
711 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
712 dev->device->mount_point, dev->print_name(), be.strerror());
716 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
718 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
719 dev->dev_errno = EIO;
720 Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n",
721 dev->device->mount_point, dev->print_name());
725 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
726 result->d_name, dev->VolCatInfo.VolCatName);
727 if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
728 /* Found the file, checking it is empty */
729 POOL_MEM filename(PM_FNAME);
730 pm_strcpy(filename, dev->device->mount_point);
731 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
732 pm_strcat(filename, "/");
734 pm_strcat(filename, dev->VolCatInfo.VolCatName);
735 if (stat(filename.c_str(), &filestat) < 0) {
737 dev->dev_errno = errno;
738 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
739 filename.c_str(), be.strerror());
742 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n",
743 filename.c_str(), filestat.st_size);
744 matched = (filestat.st_size == 0);
752 Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
755 /* There is more than 3 files (., .., and the volume file) */
763 * Edit codes into (Un)MountCommand, Write(First)PartCommand
765 * %a = archive device name
766 * %e = erase (set if cannot mount and first part)
768 * %v = last part name
770 * omsg = edited output message
771 * imsg = input string containing edit codes (%x)
774 static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
780 POOL_MEM archive_name(PM_FNAME);
783 Dmsg1(800, "edit_device_codes: %s\n", imsg);
784 for (p=imsg; *p; p++) {
794 if (dev->part == 0) {
801 bsnprintf(add, sizeof(add), "%d", dev->part);
805 str = dev->device->mount_point;
808 make_spooled_dvd_filename(dev, archive_name);
809 str = archive_name.c_str();
823 Dmsg1(1900, "add_str %s\n", str);
824 pm_strcat(omsg, (char *)str);
825 Dmsg1(1800, "omsg=%s\n", omsg.c_str());