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 ammended 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 char *edit_device_codes_dev(DEVICE *dev, char *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);
42 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
44 /* Use the working directory if spool directory is not defined */
45 if (dev->device->spool_directory) {
46 pm_strcpy(archive_name, dev->device->spool_directory);
48 pm_strcpy(archive_name, working_directory);
50 add_file_and_part_name(dev, archive_name);
53 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
56 if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
57 pm_strcat(archive_name, "/");
60 pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
61 /* if part != 0, append .# to the filename (where # is the part number) */
63 pm_strcat(archive_name, ".");
64 bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
65 pm_strcat(archive_name, partnumber);
67 Dmsg1(100, "Exit make_dvd_filename: arch=%s\n", archive_name.c_str());
71 * If timeout, wait until the mount command returns 0.
72 * If !timeout, try to mount the device only once.
74 bool mount_dev(DEVICE* dev, int timeout)
76 Dmsg0(900, "Enter mount_dev\n");
77 if (dev->is_mounted()) {
79 } else if (dev->requires_mount()) {
80 return do_mount_dev(dev, 1, timeout);
86 * If timeout, wait until the unmount command returns 0.
87 * If !timeout, try to unmount the device only once.
89 bool unmount_dev(DEVICE *dev, int timeout)
91 Dmsg0(900, "Enter unmount_dev\n");
92 if (dev->is_mounted()) {
93 return do_mount_dev(dev, 0, timeout);
98 /* (Un)mount the device */
99 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout)
101 POOL_MEM ocmd(PM_FNAME);
107 if (dev->is_mounted()) {
110 icmd = dev->device->mount_command;
112 if (!dev->is_mounted()) {
115 icmd = dev->device->unmount_command;
118 edit_device_codes_dev(dev, ocmd.c_str(), icmd);
120 Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
123 /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
128 results = get_pool_memory(PM_MESSAGE);
130 /* If busy retry each second */
131 while ((status = run_program_full_output(ocmd.c_str(),
132 dev->max_open_wait/2, results)) != 0) {
133 Dmsg1(100, "results len=%d\n", strlen(results));
134 if (fnmatch("*is already mounted on", results, 0) == 0) {
138 /* Sometimes the device cannot be mounted because it is already mounted.
139 * Try to unmount it, then remount it */
141 Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
142 do_mount_dev(dev, 0, 0);
147 Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
148 Mmsg(dev->errmsg, "Device %s cannot be mounted. ERR=%s\n",
149 dev->print_name(), results);
152 * Now, just to be sure it is not mounted, try to read the
156 struct dirent *entry, *result;
160 name_max = pathconf(".", _PC_NAME_MAX);
161 if (name_max < 1024) {
165 if (!(dp = opendir(dev->device->mount_point))) {
167 dev->dev_errno = errno;
168 Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror());
172 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
174 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
175 dev->dev_errno = ENOENT;
176 Dmsg2(29, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name);
184 mount = 1; /* If we got more than . and .. */
185 break; /* there must be something mounted */
189 free_pool_memory(results);
193 dev->set_mounted(mount); /* set/clear mounted flag */
194 free_pool_memory(results);
198 /* Update the free space on the device */
199 void update_free_space_dev(DEVICE* dev)
201 POOL_MEM ocmd(PM_FNAME);
208 icmd = dev->device->free_space_command;
212 dev->free_space_errno = 0;
214 Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno);
218 edit_device_codes_dev(dev, ocmd.c_str(), icmd);
220 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
222 results = get_pool_memory(PM_MESSAGE);
225 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
229 if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
230 Dmsg1(100, "results len=%d\n", strlen(results));
231 Dmsg1(100, "Free space program run : %s\n", results);
232 free = str_to_int64(results);
234 dev->free_space = free;
235 dev->free_space_errno = 1;
237 Mmsg0(dev->errmsg, "");
242 dev->free_space_errno = -EPIPE;
243 Mmsg1(dev->errmsg, "Cannot run free space command (%s)\n", results);
246 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
247 "free_space_errno=%d ERR=%s\n", dev->dev_name,
248 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
254 dev->dev_errno = -dev->free_space_errno;
255 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
256 "free_space_errno=%d ERR=%s\n",
257 dev->dev_name, edit_uint64(dev->free_space, ed1),
258 dev->free_space_errno, dev->errmsg);
262 free_pool_memory(results);
263 Dmsg3(29, "update_free_space_dev: free_space=%s, free_space_errno=%d have_media=%d\n",
264 edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->have_media());
269 * Write a part (Vol, Vol.1, ...) from the spool to the DVD
271 static bool dvd_write_part(DCR *dcr)
273 DEVICE *dev = dcr->dev;
274 Dmsg1(29, "dvd_write_part: device is %s\n", dev->print_name());
276 if (unmount_dev(dev, 1) < 0) {
277 Dmsg0(29, "dvd_write_part: unable to unmount the device\n");
280 POOL_MEM ocmd(PM_FNAME);
288 results = get_pool_memory(PM_MESSAGE);
290 icmd = dev->device->write_part_command;
293 * Note! part is used to control whether or not we create a
294 * new filesystem. If the device could be mounted, it is because
295 * it already has a filesystem, so we artificially set part=1
296 * to avoid zapping an existing filesystem.
299 if (dev->is_mounted() && dev->part == 0) {
300 dev->part = 1; /* do not wipe out existing filesystem */
302 edit_device_codes_dev(dev, ocmd.c_str(), icmd);
305 /* Wait at most the time a maximum size part is written in DVD 0.5x speed
306 * FIXME: Minimum speed should be in device configuration
308 timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
310 Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
312 status = run_program_full_output(ocmd.c_str(), timeout, results);
313 Dmsg1(100, "results len=%d\n", strlen(results));
315 Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s",
317 Dmsg1(000, "%s", dev->errmsg);
318 dev->dev_errno = EIO;
319 free_pool_memory(results);
323 POOL_MEM archive_name(PM_FNAME);
324 /* Delete spool file */
325 make_spooled_dvd_filename(dev, archive_name);
326 unlink(archive_name.c_str());
327 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
328 free_pool_memory(results);
329 update_free_space_dev(dev);
330 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
331 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
335 /* Open the next part file.
337 * - Increment part number
338 * - Reopen the device
340 int open_next_part(DCR *dcr)
342 DEVICE *dev = dcr->dev;
344 Dmsg5(29, "Enter: open_next_part part=%d npart=%d dev=%s vol=%s mode=%d\n",
345 dev->part, dev->num_parts, dev->print_name(),
346 dev->VolCatInfo.VolCatName, dev->openmode);
347 /* When appending, do not open a new part if the current is empty */
348 if (dev->can_append() && (dev->part == dev->num_parts) &&
349 (dev->part_size == 0)) {
350 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
362 * If we have a part open for write, then write it to
363 * DVD before opening the next part.
365 if (dev->is_dvd() && (dev->part == dev->num_parts) && dev->can_append()) {
366 if (!dvd_write_part(dcr)) {
371 dev->part_start += dev->part_size;
374 Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
375 if ((dev->num_parts < dev->part) && dev->can_append()) {
376 POOL_MEM archive_name(PM_FNAME);
380 * First check what is on DVD. If out part is there, we
381 * are in trouble, so bail out.
383 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
384 if (stat(archive_name.c_str(), &buf) == 0) {
385 /* bad news bail out */
386 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
387 archive_name.c_str());
391 dev->num_parts = dev->part;
392 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
394 /* Check if the next part exists in spool directory . */
395 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
396 Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
397 /* Then try to unlink it */
398 if (unlink(archive_name.c_str()) < 0) {
400 dev->dev_errno = errno;
401 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
402 archive_name.c_str(), be.strerror());
408 Dmsg2(50, "Call dev->open(vol=%s, mode=%d", dev->VolCatInfo.VolCatName,
411 if (dev->open(dcr, dev->openmode) < 0) {
414 dev->set_labeled(); /* all next parts are "labeled" */
418 /* Open the first part file.
420 * - Reopen the device
422 * I don't see why this is necessary unless the current
425 int open_first_part(DCR *dcr, int mode)
427 DEVICE *dev = dcr->dev;
428 Dmsg3(29, "Enter: open_first_part dev=%s Vol=%s mode=%d\n", dev->dev_name,
429 dev->VolCatInfo.VolCatName, dev->openmode);
439 Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
441 if (dev->open(dcr, mode) < 0) {
442 Dmsg0(50, "open dev() failed\n");
445 Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
450 /* Protected version of lseek, which opens the right part if necessary */
451 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
456 if (dev->num_parts == 0) { /* If there is only one part, simply call lseek. */
457 return lseek(dev->fd, offset, whence);
460 dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
463 Dmsg1(100, "lseek_dev SEEK_SET to %d\n", (int)offset);
464 if ((uint64_t)offset >= dev->part_start) {
465 if ((uint64_t)(offset - dev->part_start) < dev->part_size) {
466 /* We are staying in the current part, just seek */
467 if ((pos = lseek(dev->fd, (off_t)(offset-dev->part_start), SEEK_SET)) < 0) {
470 return pos + dev->part_start;
473 /* Load next part, and start again */
474 if (open_next_part(dcr) < 0) {
475 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
478 return lseek_dev(dev, offset, SEEK_SET);
481 /* pos < dev->part_start :
482 * We need to access a previous part,
483 * so just load the first one, and seek again
484 * until the right one is loaded */
485 if (open_first_part(dcr, dev->openmode) < 0) {
486 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
489 return lseek_dev(dev, offset, SEEK_SET);
493 Dmsg1(100, "lseek_dev SEEK_CUR to %d\n", (int)offset);
494 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
497 pos += dev->part_start;
500 } else { /* Not used in Bacula, but should work */
501 return lseek_dev(dev, pos, SEEK_SET);
505 Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset);
506 if (offset > 0) { /* Not used by bacula */
507 Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset);
512 if (dev->part == dev->num_parts) { /* The right part is already loaded */
513 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
516 return pos + dev->part_start;
519 /* Load the first part, then load the next until we reach the last one.
520 * This is the only way to be sure we compute the right file address. */
521 /* Save previous openmode, and open all but last part read-only (useful for DVDs) */
522 openmode = dev->openmode;
524 /* Works because num_parts > 0. */
525 if (open_first_part(dcr, OPEN_READ_ONLY) < 0) {
526 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
529 while (dev->part < (dev->num_parts-1)) {
530 if (open_next_part(dcr) < 0) {
531 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
535 dev->openmode = openmode;
536 if (open_next_part(dcr) < 0) {
537 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
540 return lseek_dev(dev, 0, SEEK_END);
549 bool dvd_close_job(DCR *dcr)
551 DEVICE *dev = dcr->dev;
555 /* If the device is a dvd and WritePartAfterJob
556 * is set to yes, open the next part, so, in case of a device
557 * that requires mount, it will be written to the device.
559 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
560 Dmsg0(100, "Writing last part because write_part_after_job is set.\n");
561 if (dev->part < dev->num_parts) {
562 Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
563 dev->part, dev->num_parts, dev->print_name());
564 dev->dev_errno = EIO;
568 /* This should be !dvd_write_part(dcr) */
569 if (ok && open_next_part(dcr) < 0) {
570 // if (ok && !dvd_write_part(dcr)) {
571 Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
572 dev->print_name(), strerror_dev(dev));
573 dev->dev_errno = EIO;
577 dev->VolCatInfo.VolCatParts = dev->num_parts;
583 * Edit codes into (Un)MountCommand, Write(First)PartCommand
585 * %a = archive device name
587 * %v = last part name
589 * omsg = edited output message
590 * imsg = input string containing edit codes (%x)
593 static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg)
599 POOL_MEM archive_name(PM_FNAME);
602 Dmsg1(800, "edit_device_codes: %s\n", imsg);
603 for (p=imsg; *p; p++) {
610 bsnprintf(add, sizeof(add), "%d", dev->part);
617 str = dev->device->mount_point;
620 make_spooled_dvd_filename(dev, archive_name);
621 str = archive_name.c_str();
635 Dmsg1(1900, "add_str %s\n", str);
636 pm_strcat(&omsg, (char *)str);
637 Dmsg1(1800, "omsg=%s\n", omsg);