/* * Open the device with the operating system and * initialize buffer pointers. * * Returns: true on success * false on error * * Note, for a tape, the VolName is the name we give to the * volume (not really used here), but for a file, the * VolName represents the name of the file to be created/opened. * In the case of a file, the full name is the device name * (archive_name) with the VolName concatenated. */ bool DEVICE::open(DCR *dcr, int omode) { char preserve[ST_BYTES]; clear_all_bits(ST_MAX, preserve); if (is_open()) { if (open_mode == omode) { return true; } else { d_close(m_fd); clear_opened(); Dmsg0(100, "Close fd for mode change.\n"); if (bit_is_set(ST_LABEL, state)) set_bit(ST_LABEL, preserve); if (bit_is_set(ST_APPENDREADY, state)) set_bit(ST_APPENDREADY, preserve); if (bit_is_set(ST_READREADY, state)) set_bit(ST_READREADY, preserve); } } if (dcr) { dcr->setVolCatName(dcr->VolumeName); VolCatInfo = dcr->VolCatInfo; /* structure assign */ } Dmsg4(100, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type, print_name(), getVolCatName(), mode_to_str(omode)); clear_bit(ST_LABEL, state); clear_bit(ST_APPENDREADY, state); clear_bit(ST_READREADY, state); clear_bit(ST_EOT, state); clear_bit(ST_WEOT, state); clear_bit(ST_EOF, state); label_type = B_BAREOS_LABEL; /* * We are about to open the device so let any plugin know we are. */ if (dcr && generate_plugin_event(dcr->jcr, bsdEventDeviceOpen, dcr) != bRC_OK) { Dmsg0(100, "open_dev: bsdEventDeviceOpen failed\n"); return false; } Dmsg1(100, "call open_device mode=%s\n", mode_to_str(omode)); open_device(dcr, omode); /* * Reset any important state info */ clone_bits(ST_MAX, preserve, state); Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, m_fd); return m_fd >= 0; }
/* * Close the device */ bool DEVICE::close() { bool ok = true; Dmsg4(40, "close_dev vol=%s fd=%d dev=%p dev=%s\n", VolHdr.VolumeName, m_fd, this, print_name()); offline_or_rewind(); if (!is_open()) { Dmsg2(200, "device %s already closed vol=%s\n", print_name(), VolHdr.VolumeName); return true; /* already closed */ } switch (dev_type) { case B_VTL_DEV: case B_VTAPE_DEV: case B_TAPE_DEV: unlock_door(); /* Fall through wanted */ default: if (d_close(m_fd) != 0) { berrno be; dev_errno = errno; Mmsg2(errmsg, _("Error closing device %s. ERR=%s.\n"), print_name(), be.bstrerror()); ok = false; } break; } unmount(1); /* do unmount if required */ /* Clean up device packet so it can be reused */ clear_opened(); /* * Be careful not to clear items needed by the DVD driver * when it is closing a single part. */ state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF| ST_NOSPACE|ST_MOUNTED|ST_MEDIA|ST_SHORT); label_type = B_BACULA_LABEL; file = block_num = 0; file_size = 0; file_addr = 0; EndFile = EndBlock = 0; openmode = 0; clear_volhdr(); memset(&VolCatInfo, 0, sizeof(VolCatInfo)); if (tid) { stop_thread_timer(tid); tid = 0; } return ok; }
/* * Open a device. */ void DEVICE::open_device(DCR *dcr, int omode) { POOL_MEM archive_name(PM_FNAME); get_autochanger_loaded_slot(dcr); /* * Handle opening of File Archive (not a tape) */ pm_strcpy(archive_name, dev_name); /* * If this is a virtual autochanger (i.e. changer_res != NULL) we simply use * the device name, assuming it has been appropriately setup by the "autochanger". */ if (!device->changer_res || device->changer_command[0] == 0) { if (VolCatInfo.VolCatName[0] == 0) { Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"), print_name()); clear_opened(); return; } if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) { pm_strcat(archive_name, "/"); } pm_strcat(archive_name, getVolCatName()); } mount(dcr, 1); /* do mount if required */ open_mode = omode; set_mode(omode); /* * If creating file, give 0640 permissions */ Dmsg3(100, "open disk: mode=%s open(%s, 0x%x, 0640)\n", mode_to_str(omode), archive_name.c_str(), oflags); if ((m_fd = d_open(archive_name.c_str(), oflags, 0640)) < 0) { berrno be; dev_errno = errno; Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), be.bstrerror()); Dmsg1(100, "open failed: %s", errmsg); } if (m_fd >= 0) { dev_errno = 0; file = 0; file_addr = 0; } Dmsg1(100, "open dev: disk fd=%d opened\n", m_fd); }
/* * Open the device with the operating system and * initialize buffer pointers. * * Returns: true on success * false on error * * Note, for a tape, the VolName is the name we give to the * volume (not really used here), but for a file, the * VolName represents the name of the file to be created/opened. * In the case of a file, the full name is the device name * (archive_name) with the VolName concatenated. */ bool DEVICE::open(DCR *dcr, int omode) { int preserve = 0; if (is_open()) { if (openmode == omode) { return true; } else { Dmsg1(200, "Close fd=%d for mode change in open().\n", m_fd); d_close(m_fd); clear_opened(); preserve = state & (ST_LABEL|ST_APPEND|ST_READ); } } if (dcr) { dcr->setVolCatName(dcr->VolumeName); VolCatInfo = dcr->VolCatInfo; /* structure assign */ } state &= ~(ST_NOSPACE|ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); label_type = B_BACULA_LABEL; if (is_tape() || is_fifo()) { open_tape_device(dcr, omode); } else if (is_ftp()) { open_device(dcr, omode); } else { Dmsg1(100, "call open_file_device mode=%s\n", mode_to_str(omode)); open_file_device(dcr, omode); } state |= preserve; /* reset any important state info */ Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, m_fd); Dmsg7(100, "open dev: fd=%d dev=%p dcr=%p vol=%s type=%d dev_name=%s mode=%s\n", m_fd, getVolCatName(), this, dcr, dev_type, print_name(), mode_to_str(omode)); return m_fd >= 0; }
/* * Close the device. */ bool DEVICE::close(DCR *dcr) { bool retval = true; int status; Dmsg1(100, "close_dev %s\n", print_name()); if (!is_open()) { Dmsg2(100, "device %s already closed vol=%s\n", print_name(), VolHdr.VolumeName); goto bail_out; /* already closed */ } if (!norewindonclose) { offline_or_rewind(); } switch (dev_type) { case B_VTL_DEV: case B_TAPE_DEV: unlock_door(); /* * Fall through wanted */ default: status = d_close(m_fd); if (status < 0) { berrno be; Mmsg2(errmsg, _("Unable to close device %s. ERR=%s\n"), print_name(), be.bstrerror()); dev_errno = errno; retval = false; } break; } unmount(dcr, 1); /* do unmount if required */ /* * Clean up device packet so it can be reused. */ clear_opened(); clear_bit(ST_LABEL, state); clear_bit(ST_READREADY, state); clear_bit(ST_APPENDREADY, state); clear_bit(ST_EOT, state); clear_bit(ST_WEOT, state); clear_bit(ST_EOF, state); clear_bit(ST_MOUNTED, state); clear_bit(ST_MEDIA, state); clear_bit(ST_SHORT, state); label_type = B_BAREOS_LABEL; file = block_num = 0; file_size = 0; file_addr = 0; EndFile = EndBlock = 0; open_mode = 0; clear_volhdr(); memset(&VolCatInfo, 0, sizeof(VolCatInfo)); if (tid) { stop_thread_timer(tid); tid = 0; } /* * We closed the device so let any plugin know we did. */ if (dcr) { generate_plugin_event(dcr->jcr, bsdEventDeviceClose, dcr); } bail_out: return retval; }
/* * Open a tape device */ void generic_tape_device::open_device(DCR *dcr, int omode) { file_size = 0; int timeout = max_open_wait; #if !defined(HAVE_WIN32) struct mtop mt_com; utime_t start_time = time(NULL); #endif mount(dcr, 1); /* do mount if required */ Dmsg0(100, "Open dev: device is tape\n"); get_autochanger_loaded_slot(dcr); open_mode = omode; set_mode(omode); if (timeout < 1) { timeout = 1; } errno = 0; Dmsg2(100, "Try open %s mode=%s\n", prt_name, mode_to_str(omode)); #if defined(HAVE_WIN32) /* * Windows Code */ if ((m_fd = d_open(dev_name, oflags, 0)) < 0) { dev_errno = errno; } #else /* * UNIX Code * * If busy retry each second for max_open_wait seconds */ for ( ;; ) { /* * Try non-blocking open */ m_fd = d_open(dev_name, oflags | O_NONBLOCK, 0); if (m_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 { /* * Tape open, now rewind it */ Dmsg0(100, "Rewind after open\n"); mt_com.mt_op = MTREW; mt_com.mt_count = 1; /* * Rewind only if dev is a tape */ if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { berrno be; dev_errno = errno; /* set error status from rewind */ d_close(m_fd); clear_opened(); Dmsg2(100, "Rewind error on %s close: ERR=%s\n", prt_name, be.bstrerror(dev_errno)); /* * If we get busy, device is probably rewinding, try again */ if (dev_errno != EBUSY) { break; /* error -- no medium */ } } else { /* * Got fd and rewind worked, so we must have medium in drive */ d_close(m_fd); m_fd = d_open(dev_name, oflags, 0); /* open normally */ if (m_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; lock_door(); set_os_device_parameters(dcr); /* do system dependent stuff */ break; /* Successfully opened and rewound */ } } bmicrosleep(5, 0); /* * Exceed wait time ? */ if (time(NULL) - start_time >= max_open_wait) { break; /* yes, get out */ } } #endif if (!is_open()) { berrno be; Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"), prt_name, be.bstrerror(dev_errno)); Dmsg1(100, "%s", errmsg); } Dmsg1(100, "open dev: tape %d opened\n", m_fd); }
/* * Rewind the device. * * Returns: true on success * false on failure */ bool generic_tape_device::rewind(DCR *dcr) { struct mtop mt_com; unsigned int i; bool first = true; Dmsg3(400, "rewind res=%d fd=%d %s\n", num_reserved(), m_fd, prt_name); state &= ~(ST_EOT | ST_EOF | ST_WEOT); /* Remove EOF/EOT flags */ block_num = file = 0; file_size = 0; file_addr = 0; if (m_fd < 0) { return false; } mt_com.mt_op = MTREW; mt_com.mt_count = 1; /* * If we get an I/O error on rewind, it is probably because * the drive is actually busy. We loop for (about 5 minutes) * retrying every 5 seconds. */ for (i = max_rewind_wait; ; i -= 5) { if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) { berrno be; clrerror(mt_com.mt_op); if (i == max_rewind_wait) { Dmsg1(200, "Rewind error, %s. retrying ...\n", be.bstrerror()); } /* * This is a gross hack, because if the user has the * device mounted (i.e. open), then uses mtx to load * a tape, the current open file descriptor is invalid. * So, we close the drive and re-open it. */ if (first && dcr) { int oo_mode = open_mode; d_close(m_fd); clear_opened(); open(dcr, oo_mode); if (m_fd < 0) { return false; } first = false; continue; } #ifdef HAVE_SUN_OS if (dev_errno == EIO) { Mmsg1(errmsg, _("No tape loaded or drive offline on %s.\n"), prt_name); return false; } #else if (dev_errno == EIO && i > 0) { Dmsg0(200, "Sleeping 5 seconds.\n"); bmicrosleep(5, 0); continue; } #endif Mmsg2(errmsg, _("Rewind error on %s. ERR=%s.\n"), prt_name, be.bstrerror()); return false; } break; } return true; }