diff options
Diffstat (limited to 'core/src/stored/backends/win32_fifo_device.cc')
-rw-r--r-- | core/src/stored/backends/win32_fifo_device.cc | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/core/src/stored/backends/win32_fifo_device.cc b/core/src/stored/backends/win32_fifo_device.cc new file mode 100644 index 000000000..cb4ad27fa --- /dev/null +++ b/core/src/stored/backends/win32_fifo_device.cc @@ -0,0 +1,324 @@ +/* + BAREOSĀ® - Backup Archiving REcovery Open Sourced + + Copyright (C) 2000-2012 Free Software Foundation Europe e.V. + Copyright (C) 2013-2013 Planets Communications B.V. + Copyright (C) 2013-2022 Bareos GmbH & Co. KG + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +/* + * Kern Sibbald, MM + * Extracted from other source files Marco van Wieringen, December 2013 + */ +/** + * @file + * UNIX FIFO API device abstraction. + * + */ + +#include "include/bareos.h" +#include "win32_fifo_device.h" +#include "lib/berrno.h" +#include "stored/device_control_record.h" +#include "stored/stored.h" +#include "stored/autochanger.h" +#include "stored/sd_backends.h" + +namespace storagedaemon { + +void win32_fifo_device::OpenDevice(DeviceControlRecord* dcr, DeviceMode omode) +{ + file_size = 0; + int timeout = max_open_wait; + utime_t start_time = time(NULL); + + mount(dcr, 1); /* do mount if required */ + + Dmsg0(100, "Open dev: device is fifo\n"); + + GetAutochangerLoadedSlot(dcr); + + open_mode = omode; + set_mode(omode); + + if (timeout < 1) { timeout = 1; } + errno = 0; + + if (timeout) { + // Set open timer + tid = start_thread_timer(dcr->jcr, pthread_self(), timeout); + } + + Dmsg2(100, "Try open %s mode=%s\n", prt_name, mode_to_str(omode)); + + // If busy retry each second for max_open_wait seconds + for (;;) { + // Try non-blocking open + fd = d_open(archive_device_string, oflags | O_NONBLOCK, 0); + if (fd < 0) { + BErrNo be; + dev_errno = errno; + Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n", + prt_name, omode, oflags, errno, be.bstrerror()); + } else { + d_close(fd); + fd = d_open(archive_device_string, oflags, 0); /* open normally */ + if (fd < 0) { + BErrNo be; + dev_errno = errno; + Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n", + prt_name, omode, oflags, errno, be.bstrerror()); + break; + } + dev_errno = 0; + LockDoor(); + break; /* Successfully opened and rewound */ + } + Bmicrosleep(5, 0); + + // Exceed wait time ? + if (time(NULL) - start_time >= max_open_wait) { break; /* yes, get out */ } + } + + if (!IsOpen()) { + BErrNo be; + Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"), prt_name, + be.bstrerror(dev_errno)); + Dmsg1(100, "%s", errmsg); + } + + // Stop any open() timer we started + if (tid) { + StopThreadTimer(tid); + tid = 0; + } + + Dmsg1(100, "open dev: fifo %d opened\n", fd); +} + +bool win32_fifo_device::eod(DeviceControlRecord*) +{ + if (fd < 0) { + dev_errno = EBADF; + Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), prt_name); + return false; + } + + Dmsg0(100, "Enter eod\n"); + if (AtEot()) { return true; } + + ClearEof(); /* remove EOF flag */ + + block_num = file = 0; + file_size = 0; + file_addr = 0; + return true; +} + +// (Un)mount the device (For a FILE device) +bool win32_fifo_device::do_mount(DeviceControlRecord* dcr, + bool mount, + int dotimeout) +{ + PoolMem ocmd(PM_FNAME); + POOLMEM* results; + DIR* dp; + char* icmd; + struct dirent* result; +#ifdef USE_READDIR_R + struct dirent* entry; +#endif + int status, tries, name_max, count; + BErrNo be; + + if (mount) { + icmd = device_resource->mount_command; + } else { + icmd = device_resource->unmount_command; + } + + EditMountCodes(ocmd, icmd); + + Dmsg2(100, "do_mount: cmd=%s mounted=%d\n", ocmd.c_str(), IsMounted()); + + if (dotimeout) { + /* Try at most 10 times to (un)mount the device. This should perhaps be + * configurable. */ + tries = 10; + } else { + tries = 1; + } + results = GetMemory(4000); + + /* If busy retry each second */ + Dmsg1(100, "do_mount run_prog=%s\n", ocmd.c_str()); + while ( + (status = RunProgramFullOutput(ocmd.c_str(), max_open_wait / 2, results)) + != 0) { + /* Doesn't work with internationalization (This is not a problem) */ + if (mount && fnmatch("*is already mounted on*", results, 0) == 0) { break; } + if (!mount && fnmatch("* not mounted*", results, 0) == 0) { break; } + if (tries-- > 0) { + /* Sometimes the device cannot be mounted because it is already mounted. + * Try to unmount it, then remount it */ + if (mount) { + Dmsg1(400, "Trying to unmount the device %s...\n", print_name()); + do_mount(dcr, 0, 0); + } + Bmicrosleep(1, 0); + continue; + } + Dmsg5(100, "Device %s cannot be %smounted. status=%d result=%s ERR=%s\n", + print_name(), (mount ? "" : "un"), status, results, + be.bstrerror(status)); + Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), print_name(), + (mount ? "" : "un"), be.bstrerror(status)); + + // Now, just to be sure it is not mounted, try to read the filesystem. + name_max = pathconf(".", _PC_NAME_MAX); + if (name_max < 1024) { name_max = 1024; } + + if (!(dp = opendir(device_resource->mount_point))) { + BErrNo be; + dev_errno = errno; + Dmsg3(100, "do_mount: failed to open dir %s (dev=%s), ERR=%s\n", + device_resource->mount_point, print_name(), be.bstrerror()); + goto get_out; + } +#ifdef USE_READDIR_R + entry = (struct dirent*)malloc(sizeof(struct dirent) + name_max + 1000); +#endif + count = 0; + while (1) { +#ifdef USE_READDIR_R + if ((Readdir_r(dp, entry, &result) != 0) || (result == NULL)) { +#else + result = readdir(dp); + if (result == NULL) { +#endif + dev_errno = EIO; + Dmsg2(129, + "do_mount: failed to find suitable file in dir %s (dev=%s)\n", + device_resource->mount_point, print_name()); + break; + } + if (!bstrcmp(result->d_name, ".") && !bstrcmp(result->d_name, "..") + && !bstrcmp(result->d_name, ".keep")) { + count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */ + break; + } else { + Dmsg2(129, "do_mount: ignoring %s in %s\n", result->d_name, + device_resource->mount_point); + } + } +#ifdef USE_READDIR_R + free(entry); +#endif + closedir(dp); + + Dmsg1(100, + "do_mount: got %d files in the mount point (not counting ., .. and " + ".keep)\n", + count); + + if (count > 0) { + /* If we got more than ., .. and .keep */ + /* there must be something mounted */ + if (mount) { + Dmsg1(100, "Did Mount by count=%d\n", count); + break; + } else { + /* An unmount request. We failed to unmount - report an error */ + FreePoolMemory(results); + Dmsg0(200, "== error mount=1 wanted unmount\n"); + return false; + } + } + get_out: + FreePoolMemory(results); + Dmsg0(200, "============ mount=0\n"); + return false; + } + + FreePoolMemory(results); + Dmsg1(200, "============ mount=%d\n", mount); + return true; +} + +/** + * Mount the device. + * + * If timeout, wait until the mount command returns 0. + * If !timeout, try to mount the device only once. + */ +bool win32_fifo_device::MountBackend(DeviceControlRecord* dcr, int timeout) +{ + bool retval = true; + + if (RequiresMount() && device_resource->mount_command) { + retval = do_mount(dcr, true, timeout); + } + + return retval; +} + +/** + * Unmount the device + * + * If timeout, wait until the unmount command returns 0. + * If !timeout, try to unmount the device only once. + */ +bool win32_fifo_device::UnmountBackend(DeviceControlRecord* dcr, int timeout) +{ + bool retval = true; + + if (RequiresMount() && device_resource->unmount_command) { + retval = do_mount(dcr, false, timeout); + } + + return retval; +} + +int win32_fifo_device::d_open(const char* pathname, int flags, int mode) +{ + return ::open(pathname, flags, mode); +} + +ssize_t win32_fifo_device::d_read(int fd, void* buffer, size_t count) +{ + return ::read(fd, buffer, count); +} + +ssize_t win32_fifo_device::d_write(int fd, const void* buffer, size_t count) +{ + return ::write(fd, buffer, count); +} + +int win32_fifo_device::d_close(int fd) { return ::close(fd); } + +int win32_fifo_device::d_ioctl(int, ioctl_req_t, char*) { return -1; } + +boffset_t win32_fifo_device::d_lseek(DeviceControlRecord*, boffset_t, int) +{ + return -1; +} + +bool win32_fifo_device::d_truncate(DeviceControlRecord*) { return true; } + +REGISTER_SD_BACKEND(fifo, win32_fifo_device); + +} /* namespace storagedaemon */ |