X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fdvd.c;h=b6af336243fbe13ba13d81a057329745b88817db;hb=a038cf98053a0bd2b0cfcd073d911ef1bd09b7bc;hp=7cda72f7d5b43328bfba7ccb0b8ad3a9627e84c2;hpb=24b9e858ee8080fee1e5cc3926c433d2059cf0ca;p=bacula%2Fbacula diff --git a/bacula/src/stored/dvd.c b/bacula/src/stored/dvd.c index 7cda72f7d5..b6af336243 100644 --- a/bacula/src/stored/dvd.c +++ b/bacula/src/stored/dvd.c @@ -12,7 +12,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License - version 2 as ammended with additional clauses defined in the + version 2 as amended with additional clauses defined in the file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, @@ -26,7 +26,7 @@ #include "stored.h" /* Forward referenced functions */ -static char *edit_device_codes_dev(DEVICE *dev, char *omsg, const char *imsg); +static void edit_device_codes_dev(DEVICE *dev, POOL_MEM &omsg, const char *imsg); static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout); static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name); @@ -37,6 +37,7 @@ void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name) { pm_strcpy(archive_name, dev->device->mount_point); add_file_and_part_name(dev, archive_name); + dev->set_part_spooled(false); } void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name) @@ -48,6 +49,7 @@ void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name) pm_strcpy(archive_name, working_directory); } add_file_and_part_name(dev, archive_name); + dev->set_part_spooled(true); } static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name) @@ -58,8 +60,8 @@ static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name) } pm_strcat(archive_name, dev->VolCatInfo.VolCatName); - /* if part != 0, append .# to the filename (where # is the part number) */ - if (dev->part != 0) { + /* if part > 1, append .# to the filename (where # is the part number) */ + if (dev->part > 1) { pm_strcat(archive_name, "."); bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part); pm_strcat(archive_name, partnumber); @@ -103,19 +105,22 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) char *icmd; int status, timeout; + sm_check(__FILE__, __LINE__, false); if (mount) { if (dev->is_mounted()) { + Dmsg0(200, "======= DVD mount=1\n"); return true; } icmd = dev->device->mount_command; } else { if (!dev->is_mounted()) { + Dmsg0(200, "======= DVD mount=0\n"); return true; } icmd = dev->device->unmount_command; } - edit_device_codes_dev(dev, ocmd.c_str(), icmd); + edit_device_codes_dev(dev, ocmd, icmd); Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted()); @@ -125,12 +130,11 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) } else { timeout = 0; } - results = get_pool_memory(PM_MESSAGE); + results = get_memory(2000); results[0] = 0; /* If busy retry each second */ while ((status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results)) != 0) { - Dmsg1(100, "results len=%d\n", strlen(results)); if (fnmatch("*is already mounted on", results, 0) == 0) { break; } @@ -147,7 +151,6 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results); Mmsg(dev->errmsg, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results); -#ifdef xxx /* * Now, just to be sure it is not mounted, try to read the * filesystem. @@ -165,7 +168,8 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) if (!(dp = opendir(dev->device->mount_point))) { berrno be; dev->dev_errno = errno; - Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror()); + Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n", + dev->device->mount_point, dev->print_name(), be.strerror()); goto get_out; } @@ -173,7 +177,8 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) while (1) { if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) { dev->dev_errno = ENOENT; - Dmsg2(29, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name); + Dmsg2(29, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n", + dev->device->mount_point, dev->print_name()); break; } count++; @@ -185,13 +190,17 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) break; /* there must be something mounted */ } get_out: -#endif + dev->set_mounted(false); + sm_check(__FILE__, __LINE__, false); free_pool_memory(results); + Dmsg0(200, "============ DVD mount=0\n"); return false; } dev->set_mounted(mount); /* set/clear mounted flag */ free_pool_memory(results); + update_free_space_dev(dev); + Dmsg1(200, "============ DVD mount=%d\n", mount); return true; } @@ -205,6 +214,7 @@ void update_free_space_dev(DEVICE* dev) long long int free; char ed1[50]; + sm_check(__FILE__, __LINE__, false); icmd = dev->device->free_space_command; if (!icmd) { @@ -215,19 +225,17 @@ void update_free_space_dev(DEVICE* dev) return; } - edit_device_codes_dev(dev, ocmd.c_str(), icmd); + edit_device_codes_dev(dev, ocmd, icmd); Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str()); results = get_pool_memory(PM_MESSAGE); - results[0] = 0; /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */ timeout = 3; while (1) { if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) { - Dmsg1(100, "results len=%d\n", strlen(results)); Dmsg1(100, "Free space program run : %s\n", results); free = str_to_int64(results); if (free >= 0) { @@ -244,7 +252,7 @@ void update_free_space_dev(DEVICE* dev) if (--timeout > 0) { Dmsg4(40, "Cannot get free space on device %s. free_space=%s, " - "free_space_errno=%d ERR=%s\n", dev->dev_name, + "free_space_errno=%d ERR=%s\n", dev->print_name(), edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->errmsg); bmicrosleep(1, 0); @@ -254,7 +262,7 @@ void update_free_space_dev(DEVICE* dev) dev->dev_errno = -dev->free_space_errno; Dmsg4(40, "Cannot get free space on device %s. free_space=%s, " "free_space_errno=%d ERR=%s\n", - dev->dev_name, edit_uint64(dev->free_space, ed1), + dev->print_name(), edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->errmsg); break; } @@ -262,6 +270,7 @@ void update_free_space_dev(DEVICE* dev) free_pool_memory(results); Dmsg3(29, "update_free_space_dev: free_space=%s, free_space_errno=%d have_media=%d\n", edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->have_media()); + sm_check(__FILE__, __LINE__, false); return; } @@ -271,64 +280,53 @@ void update_free_space_dev(DEVICE* dev) static bool dvd_write_part(DCR *dcr) { DEVICE *dev = dcr->dev; - Dmsg1(29, "dvd_write_part: device is %s\n", dev->print_name()); - - if (unmount_dev(dev, 1) < 0) { - Dmsg0(29, "dvd_write_part: unable to unmount the device\n"); - } - POOL_MEM ocmd(PM_FNAME); - POOLMEM *results; char* icmd; int status; int timeout; - int part; char ed1[50]; - results = get_pool_memory(PM_MESSAGE); - results[0] = 0; + sm_check(__FILE__, __LINE__, false); + Dmsg1(29, "dvd_write_part: device is %s\n", dev->print_name()); icmd = dev->device->write_part_command; - /* - * Note! part is used to control whether or not we create a - * new filesystem. If the device could be mounted, it is because - * it already has a filesystem, so we artificially set part=1 - * to avoid zapping an existing filesystem. - */ - part = dev->part; - if (dev->is_mounted() && dev->part == 0) { - dev->part = 1; /* do not wipe out existing filesystem */ - } - edit_device_codes_dev(dev, ocmd.c_str(), icmd); - dev->part = part; + edit_device_codes_dev(dev, ocmd, icmd); - /* Wait at most the time a maximum size part is written in DVD 0.5x speed + /* + * Wait at most the time a maximum size part is written in DVD 0.5x speed * FIXME: Minimum speed should be in device configuration */ timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2)); Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout); - status = run_program_full_output(ocmd.c_str(), timeout, results); - Dmsg1(100, "results len=%d\n", strlen(results)); +{ + POOL_MEM results(PM_MESSAGE); + sm_check(__FILE__, __LINE__, false); + status = run_program_full_output(ocmd.c_str(), timeout, results.c_str()); + sm_check(__FILE__, __LINE__, false); if (status != 0) { Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", - results); + results.c_str()); Dmsg1(000, "%s", dev->errmsg); dev->dev_errno = EIO; - free_pool_memory(results); return false; } + sm_check(__FILE__, __LINE__, false); +} +{ POOL_MEM archive_name(PM_FNAME); /* Delete spool file */ make_spooled_dvd_filename(dev, archive_name); unlink(archive_name.c_str()); Dmsg1(29, "unlink(%s)\n", archive_name.c_str()); - free_pool_memory(results); + sm_check(__FILE__, __LINE__, false); +} update_free_space_dev(dev); Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), edit_uint64_with_commas(dev->free_space, ed1), dev->print_name()); + sm_check(__FILE__, __LINE__, false); return true; } @@ -340,12 +338,17 @@ static bool dvd_write_part(DCR *dcr) int open_next_part(DCR *dcr) { DEVICE *dev = dcr->dev; - - Dmsg5(29, "Enter: open_next_part part=%d npart=%d dev=%s vol=%s mode=%d\n", + + Dmsg5(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d\n", dev->part, dev->num_parts, dev->print_name(), dev->VolCatInfo.VolCatName, dev->openmode); + if (!dev->is_dvd()) { + Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); + return -1; + } + /* When appending, do not open a new part if the current is empty */ - if (dev->can_append() && (dev->part == dev->num_parts) && + if (dev->can_append() && (dev->part >= dev->num_parts) && (dev->part_size == 0)) { Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n"); return dev->fd; @@ -362,20 +365,24 @@ int open_next_part(DCR *dcr) * If we have a part open for write, then write it to * DVD before opening the next part. */ - if (dev->is_dvd() && (dev->part == dev->num_parts) && dev->can_append()) { + if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) { if (!dvd_write_part(dcr)) { return -1; } } + if (dev->part > dev->num_parts) { + Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts); + ASSERT(dev->part <= dev->num_parts); + } dev->part_start += dev->part_size; dev->part++; Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts); + /* I think this dev->can_append() should not be there */ if ((dev->num_parts < dev->part) && dev->can_append()) { POOL_MEM archive_name(PM_FNAME); struct stat buf; - /* * First check what is on DVD. If out part is there, we * are in trouble, so bail out. @@ -388,7 +395,9 @@ int open_next_part(DCR *dcr) return -1; } + Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part); dev->num_parts = dev->part; + dev->VolCatInfo.VolCatParts = dev->part; make_spooled_dvd_filename(dev, archive_name); /* makes spool name */ /* Check if the next part exists in spool directory . */ @@ -404,8 +413,12 @@ int open_next_part(DCR *dcr) } } } - - Dmsg2(50, "Call dev->open(vol=%s, mode=%d", dev->VolCatInfo.VolCatName, + if (dev->num_parts < dev->part) { + Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part); + dev->num_parts = dev->part; + dev->VolCatInfo.VolCatParts = dev->part; + } + Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName, dev->openmode); /* Open next part */ if (dev->open(dcr, dev->openmode) < 0) { @@ -425,8 +438,10 @@ int open_next_part(DCR *dcr) int open_first_part(DCR *dcr, int mode) { DEVICE *dev = dcr->dev; - Dmsg3(29, "Enter: open_first_part dev=%s Vol=%s mode=%d\n", dev->dev_name, + + Dmsg3(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d\n", dev->print_name(), dev->VolCatInfo.VolCatName, dev->openmode); + if (dev->fd >= 0) { close(dev->fd); } @@ -434,7 +449,7 @@ int open_first_part(DCR *dcr, int mode) dev->clear_opened(); dev->part_start = 0; - dev->part = 0; + dev->part = 1; Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, mode); @@ -450,10 +465,13 @@ int open_first_part(DCR *dcr, int mode) /* Protected version of lseek, which opens the right part if necessary */ off_t lseek_dev(DEVICE *dev, off_t offset, int whence) { - int pos, openmode; DCR *dcr; + off_t pos; - if (dev->num_parts == 0) { /* If there is only one part, simply call lseek. */ + Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd, + dev->part, dev->num_parts); + if (!dev->is_dvd()) { + Dmsg0(100, "Using sys lseek\n"); return lseek(dev->fd, offset, whence); } @@ -462,9 +480,10 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence) case SEEK_SET: Dmsg1(100, "lseek_dev SEEK_SET to %d\n", (int)offset); if ((uint64_t)offset >= dev->part_start) { - if ((uint64_t)(offset - dev->part_start) < dev->part_size) { + offset -= dev->part_start; /* adjust for start of this part */ + if (offset == 0 || (uint64_t)offset < dev->part_size) { /* We are staying in the current part, just seek */ - if ((pos = lseek(dev->fd, (off_t)(offset-dev->part_start), SEEK_SET)) < 0) { + if ((pos = lseek(dev->fd, offset, SEEK_SET)) < 0) { return pos; } else { return pos + dev->part_start; @@ -478,10 +497,12 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence) return lseek_dev(dev, offset, SEEK_SET); } } else { - /* pos < dev->part_start : + /* + * pos < dev->part_start : * We need to access a previous part, * so just load the first one, and seek again - * until the right one is loaded */ + * until the right one is loaded + */ if (open_first_part(dcr, dev->openmode) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the first part\n"); return -1; @@ -503,24 +524,36 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence) break; case SEEK_END: Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset); + /* + * Bacula does not use offsets for SEEK_END + * Also, Bacula uses seek_end only when it wants to + * append to the volume, so for a dvd that means + * that the volume must be spooled since the DVD + * itself is read-only (as currently implemented). + */ if (offset > 0) { /* Not used by bacula */ Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset); errno = EINVAL; return -1; } - - if (dev->part == dev->num_parts) { /* The right part is already loaded */ + /* If we are already on a spooled part and have the + * right part number, simply seek + */ + if (dev->is_part_spooled() && dev->part == dev->num_parts) { if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) { return pos; } else { return pos + dev->part_start; } } else { - /* Load the first part, then load the next until we reach the last one. - * This is the only way to be sure we compute the right file address. */ - /* Save previous openmode, and open all but last part read-only (useful for DVDs) */ - openmode = dev->openmode; - + /* + * Load the first part, then load the next until we reach the last one. + * This is the only way to be sure we compute the right file address. + * + * Save previous openmode, and open all but last part read-only + * (useful for DVDs) + */ + int modesave = dev->openmode; /* Works because num_parts > 0. */ if (open_first_part(dcr, OPEN_READ_ONLY) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the first part\n"); @@ -532,7 +565,7 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence) return -1; } } - dev->openmode = openmode; + dev->openmode = modesave; if (open_next_part(dcr) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the next part\n"); return -1; @@ -557,7 +590,8 @@ bool dvd_close_job(DCR *dcr) * that requires mount, it will be written to the device. */ if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) { - Dmsg0(100, "Writing last part because write_part_after_job is set.\n"); + Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n", + dev->part); if (dev->part < dev->num_parts) { Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"), dev->part, dev->num_parts, dev->print_name()); @@ -566,14 +600,15 @@ bool dvd_close_job(DCR *dcr) } /* This should be !dvd_write_part(dcr) */ - if (ok && open_next_part(dcr) < 0) { -// if (ok && !dvd_write_part(dcr)) { +// if (ok && open_next_part(dcr) < 0) { + if (ok && !dvd_write_part(dcr)) { Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"), dev->print_name(), strerror_dev(dev)); dev->dev_errno = EIO; ok = false; } } + Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts); dev->VolCatInfo.VolCatParts = dev->num_parts; return ok; } @@ -583,6 +618,7 @@ bool dvd_close_job(DCR *dcr) * Edit codes into (Un)MountCommand, Write(First)PartCommand * %% = % * %a = archive device name + * %e = erase (set if cannot mount and first part) * %m = mount point * %v = last part name * @@ -590,7 +626,7 @@ bool dvd_close_job(DCR *dcr) * imsg = input string containing edit codes (%x) * */ -static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg) +static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg) { const char *p; const char *str; @@ -598,7 +634,7 @@ static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg) POOL_MEM archive_name(PM_FNAME); - *omsg = 0; + omsg.c_str()[0] = 0; Dmsg1(800, "edit_device_codes: %s\n", imsg); for (p=imsg; *p; p++) { if (*p == '%') { @@ -606,13 +642,20 @@ static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg) case '%': str = "%"; break; + case 'a': + str = dev->dev_name; + break; + case 'e': + if (dev->part == 1 && !dev->is_mounted()) { + str = "1"; + } else { + str = "0"; + } + break; case 'n': bsnprintf(add, sizeof(add), "%d", dev->part); str = add; break; - case 'a': - str = dev->dev_name; - break; case 'm': str = dev->device->mount_point; break; @@ -633,8 +676,7 @@ static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg) str = add; } Dmsg1(1900, "add_str %s\n", str); - pm_strcat(&omsg, (char *)str); - Dmsg1(1800, "omsg=%s\n", omsg); + pm_strcat(omsg, (char *)str); + Dmsg1(1800, "omsg=%s\n", omsg.c_str()); } - return omsg; }