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;
233 dev->clear_freespace_ok(); /* No valid freespace */
235 Dmsg2(29, "update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
236 edit_uint64(dev->free_space, ed1), dev->free_space_errno);
240 edit_device_codes_dev(dev, ocmd, icmd);
242 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
244 results = get_pool_memory(PM_MESSAGE);
246 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
250 if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
251 Dmsg1(100, "Free space program run : %s\n", results);
252 free = str_to_int64(results);
254 dev->free_space = free;
255 dev->free_space_errno = 0;
256 dev->set_freespace_ok(); /* have valid freespace */
258 Mmsg0(dev->errmsg, "");
263 dev->free_space_errno = EPIPE;
264 dev->clear_freespace_ok(); /* no valid freespace */
265 Mmsg1(dev->errmsg, _("Cannot run free space command (%s)\n"), results);
268 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
269 "free_space_errno=%d ERR=%s\n", dev->print_name(),
270 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
276 dev->dev_errno = dev->free_space_errno;
277 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
278 "free_space_errno=%d ERR=%s\n",
279 dev->print_name(), edit_uint64(dev->free_space, ed1),
280 dev->free_space_errno, dev->errmsg);
284 free_pool_memory(results);
285 Dmsg4(29, "update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
286 edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
287 sm_check(__FILE__, __LINE__, false);
292 * Write a part (Vol, Vol.1, ...) from the spool to the DVD
293 * This routine does not update the part number, so normally, you
294 * should call open_next_part()
295 * It is also called from truncate_dvd_dev to "blank" the medium, as
296 * well as from block.c when the DVD is full to write the last part.
298 bool dvd_write_part(DCR *dcr)
300 DEVICE *dev = dcr->dev;
301 POOL_MEM ocmd(PM_FNAME);
307 sm_check(__FILE__, __LINE__, false);
308 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
309 icmd = dev->device->write_part_command;
311 edit_device_codes_dev(dev, ocmd, icmd);
314 * original line follows
315 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
316 * I modified this for a longer timeout; pre-formatting, blanking and
317 * writing can take quite a while
319 timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024)*8);
321 Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
324 POOL_MEM results(PM_MESSAGE);
325 sm_check(__FILE__, __LINE__, false);
326 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
327 sm_check(__FILE__, __LINE__, false);
329 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
331 Dmsg1(000, "%s", dev->errmsg);
332 dev->dev_errno = EIO;
333 mark_volume_in_error(dcr);
336 sm_check(__FILE__, __LINE__, false);
340 POOL_MEM archive_name(PM_FNAME);
341 /* Delete spool file */
342 make_spooled_dvd_filename(dev, archive_name);
343 unlink(archive_name.c_str());
344 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
345 sm_check(__FILE__, __LINE__, false);
348 /* growisofs umounted the device, so remount it (it will update the free space) */
349 dev->clear_mounted();
351 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
352 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
353 sm_check(__FILE__, __LINE__, false);
357 /* Open the next part file.
359 * - Increment part number
360 * - Reopen the device
362 int dvd_open_next_part(DCR *dcr)
364 DEVICE *dev = dcr->dev;
366 Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
367 dev->part, dev->num_parts, dev->print_name(),
368 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
369 if (!dev->is_dvd()) {
370 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
374 /* When appending, do not open a new part if the current is empty */
375 if (dev->can_append() && (dev->part >= dev->num_parts) &&
376 (dev->part_size == 0)) {
377 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
389 * If we have a part open for write, then write it to
390 * DVD before opening the next part.
392 if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
393 if (!dvd_write_part(dcr)) {
398 if (dev->part > dev->num_parts) {
399 Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
400 ASSERT(dev->part <= dev->num_parts);
402 dev->part_start += dev->part_size;
405 Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
406 /* I think this dev->can_append() should not be there */
407 if ((dev->num_parts < dev->part) && dev->can_append()) {
408 POOL_MEM archive_name(PM_FNAME);
411 * First check what is on DVD. If our part is there, we
412 * are in trouble, so bail out.
413 * NB: This is however not a problem if we are writing the first part.
414 * It simply means that we are overriding an existing volume...
416 if (dev->num_parts > 0) {
417 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
418 if (stat(archive_name.c_str(), &buf) == 0) {
419 /* bad news bail out */
420 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
421 archive_name.c_str());
426 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
427 dev->num_parts = dev->part;
428 dev->VolCatInfo.VolCatParts = dev->part;
429 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
431 /* Check if the next part exists in spool directory . */
432 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
433 Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
434 /* Then try to unlink it */
435 if (unlink(archive_name.c_str()) < 0) {
437 dev->dev_errno = errno;
438 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
439 archive_name.c_str(), be.strerror());
444 if (dev->num_parts < dev->part) {
445 Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
446 dev->num_parts = dev->part;
447 dev->VolCatInfo.VolCatParts = dev->part;
449 Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName,
453 int append = dev->can_append();
454 if (dev->open(dcr, dev->openmode) < 0) {
457 dev->set_labeled(); /* all next parts are "labeled" */
458 if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
465 /* Open the first part file.
467 * - Reopen the device
469 int dvd_open_first_part(DCR *dcr, int mode)
471 DEVICE *dev = dcr->dev;
473 Dmsg4(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d\n", dev->print_name(),
474 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts);
485 Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
487 if (dev->open(dcr, mode) < 0) {
488 Dmsg0(50, "open dev() failed\n");
491 Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
496 /* Protected version of lseek, which opens the right part if necessary */
497 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
501 char ed1[50], ed2[50];
503 Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
504 dev->part, dev->num_parts);
505 if (!dev->is_dvd()) {
506 Dmsg0(100, "Using sys lseek\n");
507 return lseek(dev->fd, offset, whence);
510 dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
513 Dmsg2(100, "lseek_dev SEEK_SET to %s (part_start=%s)\n",
514 edit_uint64(offset, ed1), edit_uint64(dev->part_start, ed2));
515 if ((uint64_t)offset >= dev->part_start) {
516 if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
517 /* We are staying in the current part, just seek */
518 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
521 return pos + dev->part_start;
524 /* Load next part, and start again */
525 if (dvd_open_next_part(dcr) < 0) {
526 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
529 return lseek_dev(dev, offset, SEEK_SET);
533 * pos < dev->part_start :
534 * We need to access a previous part,
535 * so just load the first one, and seek again
536 * until the right one is loaded
538 if (dvd_open_first_part(dcr, dev->openmode) < 0) {
539 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
542 return lseek_dev(dev, offset, SEEK_SET);
546 Dmsg1(100, "lseek_dev SEEK_CUR to %s\n", edit_uint64(offset, ed1));
547 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
550 pos += dev->part_start;
552 Dmsg1(100, "lseek_dev SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
554 } else { /* Not used in Bacula, but should work */
555 return lseek_dev(dev, pos, SEEK_SET);
559 Dmsg1(100, "lseek_dev SEEK_END to %s\n", edit_uint64(offset, ed1));
561 * Bacula does not use offsets for SEEK_END
562 * Also, Bacula uses seek_end only when it wants to
563 * append to the volume, so for a dvd that means
564 * that the volume must be spooled since the DVD
565 * itself is read-only (as currently implemented).
567 if (offset > 0) { /* Not used by bacula */
568 Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %s\n",
569 edit_uint64(offset, ed1));
573 /* If we are already on a spooled part and have the
574 * right part number, simply seek
576 if (dev->is_part_spooled() && dev->part == dev->num_parts) {
577 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
580 Dmsg1(100, "lseek_dev SEEK_END returns %s\n",
581 edit_uint64(pos + dev->part_start, ed1));
582 return pos + dev->part_start;
586 * Load the first part, then load the next until we reach the last one.
587 * This is the only way to be sure we compute the right file address.
589 * Save previous openmode, and open all but last part read-only
592 int modesave = dev->openmode;
593 /* Works because num_parts > 0. */
594 if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
595 Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
598 if (dev->num_parts > 0) {
599 while (dev->part < (dev->num_parts-1)) {
600 if (dvd_open_next_part(dcr) < 0) {
601 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
605 dev->openmode = modesave;
606 if (dvd_open_next_part(dcr) < 0) {
607 Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
611 return lseek_dev(dev, 0, SEEK_END);
620 bool dvd_close_job(DCR *dcr)
622 DEVICE *dev = dcr->dev;
626 /* If the device is a dvd and WritePartAfterJob
627 * is set to yes, open the next part, so, in case of a device
628 * that requires mount, it will be written to the device.
630 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
631 Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
633 if (dev->part < dev->num_parts) {
634 Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
635 dev->part, dev->num_parts, dev->print_name());
636 dev->dev_errno = EIO;
640 /* This should be !dvd_write_part(dcr)
641 NB: No! If you call dvd_write_part, the part number is not updated.
642 You must open the next part, it will automatically write the part and
643 update the part number. */
644 if (ok && (dvd_open_next_part(dcr) < 0)) {
645 Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
646 dev->print_name(), strerror_dev(dev));
647 dev->dev_errno = EIO;
651 Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
652 dev->VolCatInfo.VolCatParts = dev->num_parts;
656 bool truncate_dvd_dev(DCR *dcr) {
657 DEVICE* dev = dcr->dev;
659 /* Set num_parts to zero (on disk) */
661 dcr->VolCatInfo.VolCatParts = 0;
662 dev->VolCatInfo.VolCatParts = 0;
664 Dmsg0(100, "truncate_dvd_dev: Opening first part (1)...\n");
666 dev->truncating = true;
667 if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
668 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (1).\n");
669 dev->truncating = false;
672 dev->truncating = false;
674 Dmsg0(100, "truncate_dvd_dev: Truncating...\n");
676 /* If necessary, truncate it. */
677 if (ftruncate(dev->fd, 0) != 0) {
679 Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
680 dev->print_name(), be.strerror());
688 Dmsg0(100, "truncate_dvd_dev: Opening first part (2)...\n");
690 if (!dvd_write_part(dcr)) {
691 Dmsg0(100, "truncate_dvd_dev: Error while writing to DVD.\n");
695 if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
696 Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
703 /* Checks if we can write on a non-blank DVD: meaning that it just have been
704 * truncated (there is only one zero-sized file on the DVD, with the right
706 bool check_can_write_on_non_blank_dvd(DCR *dcr) {
707 DEVICE* dev = dcr->dev;
709 struct dirent *entry, *result;
712 int matched = 0; /* We found an empty file with the right name. */
713 struct stat filestat;
715 name_max = pathconf(".", _PC_NAME_MAX);
716 if (name_max < 1024) {
720 if (!(dp = opendir(dev->device->mount_point))) {
722 dev->dev_errno = errno;
723 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
724 dev->device->mount_point, dev->print_name(), be.strerror());
728 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
730 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
731 dev->dev_errno = EIO;
732 Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n",
733 dev->device->mount_point, dev->print_name());
737 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
738 result->d_name, dev->VolCatInfo.VolCatName);
739 if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
740 /* Found the file, checking it is empty */
741 POOL_MEM filename(PM_FNAME);
742 pm_strcpy(filename, dev->device->mount_point);
743 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
744 pm_strcat(filename, "/");
746 pm_strcat(filename, dev->VolCatInfo.VolCatName);
747 if (stat(filename.c_str(), &filestat) < 0) {
749 dev->dev_errno = errno;
750 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
751 filename.c_str(), be.strerror());
754 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n",
755 filename.c_str(), filestat.st_size);
756 matched = (filestat.st_size == 0);
764 Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
767 /* There is more than 3 files (., .., and the volume file) */
775 * Edit codes into (Un)MountCommand, Write(First)PartCommand
777 * %a = archive device name
778 * %e = erase (set if cannot mount and first part)
781 * %v = last part name
783 * omsg = edited output message
784 * imsg = input string containing edit codes (%x)
787 static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
793 POOL_MEM archive_name(PM_FNAME);
796 Dmsg1(800, "edit_device_codes: %s\n", imsg);
797 for (p=imsg; *p; p++) {
807 if (dev->num_parts == 0) {
814 bsnprintf(add, sizeof(add), "%d", dev->part);
818 str = dev->device->mount_point;
821 make_spooled_dvd_filename(dev, archive_name);
822 str = archive_name.c_str();
836 Dmsg1(1900, "add_str %s\n", str);
837 pm_strcat(omsg, (char *)str);
838 Dmsg1(1800, "omsg=%s\n", omsg.c_str());