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(900, "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(900, "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 = ENOENT;
180 Dmsg2(29, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n",
181 dev->device->mount_point, dev->print_name());
189 mount = 1; /* If we got more than . and .. */
190 break; /* there must be something mounted */
193 dev->set_mounted(false);
194 sm_check(__FILE__, __LINE__, false);
195 free_pool_memory(results);
196 Dmsg0(200, "============ DVD mount=0\n");
200 dev->set_mounted(mount); /* set/clear mounted flag */
201 free_pool_memory(results);
202 update_free_space_dev(dev);
203 Dmsg1(200, "============ DVD mount=%d\n", mount);
207 /* Update the free space on the device */
208 void update_free_space_dev(DEVICE* dev)
210 POOL_MEM ocmd(PM_FNAME);
217 sm_check(__FILE__, __LINE__, false);
218 icmd = dev->device->free_space_command;
222 dev->free_space_errno = 0;
224 Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno);
228 edit_device_codes_dev(dev, ocmd, icmd);
230 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
232 results = get_pool_memory(PM_MESSAGE);
234 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
238 if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
239 Dmsg1(100, "Free space program run : %s\n", results);
240 free = str_to_int64(results);
242 dev->free_space = free;
243 dev->free_space_errno = 1;
245 Mmsg0(dev->errmsg, "");
250 dev->free_space_errno = -EPIPE;
251 Mmsg1(dev->errmsg, "Cannot run free space command (%s)\n", results);
254 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
255 "free_space_errno=%d ERR=%s\n", dev->print_name(),
256 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
262 dev->dev_errno = -dev->free_space_errno;
263 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
264 "free_space_errno=%d ERR=%s\n",
265 dev->print_name(), edit_uint64(dev->free_space, ed1),
266 dev->free_space_errno, dev->errmsg);
270 free_pool_memory(results);
271 Dmsg3(29, "update_free_space_dev: free_space=%s, free_space_errno=%d have_media=%d\n",
272 edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->have_media());
273 sm_check(__FILE__, __LINE__, false);
278 * Write a part (Vol, Vol.1, ...) from the spool to the DVD
280 static bool dvd_write_part(DCR *dcr)
282 DEVICE *dev = dcr->dev;
283 POOL_MEM ocmd(PM_FNAME);
289 sm_check(__FILE__, __LINE__, false);
290 Dmsg1(29, "dvd_write_part: device is %s\n", dev->print_name());
291 icmd = dev->device->write_part_command;
293 edit_device_codes_dev(dev, ocmd, icmd);
296 * Wait at most the time a maximum size part is written in DVD 0.5x speed
297 * FIXME: Minimum speed should be in device configuration
299 timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
301 Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
304 POOL_MEM results(PM_MESSAGE);
305 sm_check(__FILE__, __LINE__, false);
306 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
307 sm_check(__FILE__, __LINE__, false);
309 Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s",
311 Dmsg1(000, "%s", dev->errmsg);
312 dev->dev_errno = EIO;
315 sm_check(__FILE__, __LINE__, false);
319 POOL_MEM archive_name(PM_FNAME);
320 /* Delete spool file */
321 make_spooled_dvd_filename(dev, archive_name);
322 unlink(archive_name.c_str());
323 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
324 sm_check(__FILE__, __LINE__, false);
326 update_free_space_dev(dev);
327 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
328 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
329 sm_check(__FILE__, __LINE__, false);
333 /* Open the next part file.
335 * - Increment part number
336 * - Reopen the device
338 int open_next_part(DCR *dcr)
340 DEVICE *dev = dcr->dev;
342 Dmsg5(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d\n",
343 dev->part, dev->num_parts, dev->print_name(),
344 dev->VolCatInfo.VolCatName, dev->openmode);
345 if (!dev->is_dvd()) {
346 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
350 /* When appending, do not open a new part if the current is empty */
351 if (dev->can_append() && (dev->part >= dev->num_parts) &&
352 (dev->part_size == 0)) {
353 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
365 * If we have a part open for write, then write it to
366 * DVD before opening the next part.
368 if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
369 if (!dvd_write_part(dcr)) {
374 if (dev->part > dev->num_parts) {
375 Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
376 ASSERT(dev->part <= dev->num_parts);
378 dev->part_start += dev->part_size;
381 Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
382 /* I think this dev->can_append() should not be there */
383 if ((dev->num_parts < dev->part) && dev->can_append()) {
384 POOL_MEM archive_name(PM_FNAME);
387 * First check what is on DVD. If out part is there, we
388 * are in trouble, so bail out.
390 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
391 if (stat(archive_name.c_str(), &buf) == 0) {
392 /* bad news bail out */
393 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
394 archive_name.c_str());
398 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
399 dev->num_parts = dev->part;
400 dev->VolCatInfo.VolCatParts = dev->part;
401 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
403 /* Check if the next part exists in spool directory . */
404 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
405 Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
406 /* Then try to unlink it */
407 if (unlink(archive_name.c_str()) < 0) {
409 dev->dev_errno = errno;
410 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
411 archive_name.c_str(), be.strerror());
416 if (dev->num_parts < dev->part) {
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;
421 Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName,
424 if (dev->open(dcr, dev->openmode) < 0) {
427 dev->set_labeled(); /* all next parts are "labeled" */
431 /* Open the first part file.
433 * - Reopen the device
435 * I don't see why this is necessary unless the current
438 int open_first_part(DCR *dcr, int mode)
440 DEVICE *dev = dcr->dev;
442 Dmsg3(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d\n", dev->print_name(),
443 dev->VolCatInfo.VolCatName, dev->openmode);
454 Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
456 if (dev->open(dcr, mode) < 0) {
457 Dmsg0(50, "open dev() failed\n");
460 Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
465 /* Protected version of lseek, which opens the right part if necessary */
466 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
471 Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
472 dev->part, dev->num_parts);
473 if (!dev->is_dvd()) {
474 Dmsg0(100, "Using sys lseek\n");
475 return lseek(dev->fd, offset, whence);
478 dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
481 Dmsg1(100, "lseek_dev SEEK_SET to %d\n", (int)offset);
482 if ((uint64_t)offset >= dev->part_start) {
483 offset -= dev->part_start; /* adjust for start of this part */
484 if (offset == 0 || (uint64_t)offset < dev->part_size) {
485 /* We are staying in the current part, just seek */
486 if ((pos = lseek(dev->fd, offset, SEEK_SET)) < 0) {
489 return pos + dev->part_start;
492 /* Load next part, and start again */
493 if (open_next_part(dcr) < 0) {
494 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
497 return lseek_dev(dev, offset, SEEK_SET);
501 * pos < dev->part_start :
502 * We need to access a previous part,
503 * so just load the first one, and seek again
504 * until the right one is loaded
506 if (open_first_part(dcr, dev->openmode) < 0) {
507 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
510 return lseek_dev(dev, offset, SEEK_SET);
514 Dmsg1(100, "lseek_dev SEEK_CUR to %d\n", (int)offset);
515 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
518 pos += dev->part_start;
521 } else { /* Not used in Bacula, but should work */
522 return lseek_dev(dev, pos, SEEK_SET);
526 Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset);
528 * Bacula does not use offsets for SEEK_END
529 * Also, Bacula uses seek_end only when it wants to
530 * append to the volume, so for a dvd that means
531 * that the volume must be spooled since the DVD
532 * itself is read-only (as currently implemented).
534 if (offset > 0) { /* Not used by bacula */
535 Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset);
539 /* If we are already on a spooled part and have the
540 * right part number, simply seek
542 if (dev->is_part_spooled() && dev->part == dev->num_parts) {
543 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
546 return pos + dev->part_start;
550 * Load the first part, then load the next until we reach the last one.
551 * This is the only way to be sure we compute the right file address.
553 * Save previous openmode, and open all but last part read-only
556 int modesave = dev->openmode;
557 /* Works because num_parts > 0. */
558 if (open_first_part(dcr, OPEN_READ_ONLY) < 0) {
559 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
562 while (dev->part < (dev->num_parts-1)) {
563 if (open_next_part(dcr) < 0) {
564 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
568 dev->openmode = modesave;
569 if (open_next_part(dcr) < 0) {
570 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
573 return lseek_dev(dev, 0, SEEK_END);
582 bool dvd_close_job(DCR *dcr)
584 DEVICE *dev = dcr->dev;
588 /* If the device is a dvd and WritePartAfterJob
589 * is set to yes, open the next part, so, in case of a device
590 * that requires mount, it will be written to the device.
592 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
593 Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
595 if (dev->part < dev->num_parts) {
596 Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
597 dev->part, dev->num_parts, dev->print_name());
598 dev->dev_errno = EIO;
602 /* This should be !dvd_write_part(dcr) */
603 // if (ok && open_next_part(dcr) < 0) {
604 if (ok && !dvd_write_part(dcr)) {
605 Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
606 dev->print_name(), strerror_dev(dev));
607 dev->dev_errno = EIO;
611 Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
612 dev->VolCatInfo.VolCatParts = dev->num_parts;
618 * Edit codes into (Un)MountCommand, Write(First)PartCommand
620 * %a = archive device name
621 * %e = erase (set if cannot mount and first part)
623 * %v = last part name
625 * omsg = edited output message
626 * imsg = input string containing edit codes (%x)
629 static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
635 POOL_MEM archive_name(PM_FNAME);
638 Dmsg1(800, "edit_device_codes: %s\n", imsg);
639 for (p=imsg; *p; p++) {
649 if (dev->part == 1 && !dev->is_mounted()) {
656 bsnprintf(add, sizeof(add), "%d", dev->part);
660 str = dev->device->mount_point;
663 make_spooled_dvd_filename(dev, archive_name);
664 str = archive_name.c_str();
678 Dmsg1(1900, "add_str %s\n", str);
679 pm_strcat(omsg, (char *)str);
680 Dmsg1(1800, "omsg=%s\n", omsg.c_str());