int DCR::check_volume_label(bool &ask, bool &autochanger) { int vol_label_status; /* * If we are writing to a stream device, ASSUME the volume label * is correct. */ if (dev->has_cap(CAP_STREAM)) { vol_label_status = VOL_OK; create_volume_label(dev, VolumeName, "Default", false /* not DVD */); dev->VolHdr.LabelType = PRE_LABEL; } else { vol_label_status = read_dev_volume_label(this); } if (job_canceled(jcr)) { goto check_bail_out; } Dmsg2(150, "Want dirVol=%s dirStat=%s\n", VolumeName, VolCatInfo.VolCatStatus); /* * At this point, dev->VolCatInfo has what is in the drive, if anything, * and dcr->VolCatInfo has what the Director wants. */ switch (vol_label_status) { case VOL_OK: Dmsg1(150, "Vol OK name=%s\n", dev->VolHdr.VolumeName); dev->VolCatInfo = VolCatInfo; /* structure assignment */ break; /* got a Volume */ case VOL_NAME_ERROR: VOLUME_CAT_INFO dcrVolCatInfo, devVolCatInfo; char saveVolumeName[MAX_NAME_LENGTH]; Dmsg2(150, "Vol NAME Error Have=%s, want=%s\n", dev->VolHdr.VolumeName, VolumeName); if (dev->is_volume_to_unload()) { ask = true; goto check_next_volume; } /* If not removable, Volume is broken */ if (!dev->is_removable()) { Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"), VolumeName, dev->print_name()); mark_volume_in_error(); goto check_next_volume; } /* * OK, we got a different volume mounted. First save the * requested Volume info (dcr) structure, then query if * this volume is really OK. If not, put back the desired * volume name, mark it not in changer and continue. */ dcrVolCatInfo = VolCatInfo; /* structure assignment */ devVolCatInfo = dev->VolCatInfo; /* structure assignment */ /* Check if this is a valid Volume in the pool */ bstrncpy(saveVolumeName, VolumeName, sizeof(saveVolumeName)); bstrncpy(VolumeName, dev->VolHdr.VolumeName, sizeof(VolumeName)); if (!dir_get_volume_info(this, GET_VOL_INFO_FOR_WRITE)) { POOL_MEM vol_info_msg; pm_strcpy(vol_info_msg, jcr->dir_bsock->msg); /* save error message */ /* Restore desired volume name, note device info out of sync */ /* This gets the info regardless of the Pool */ bstrncpy(VolumeName, dev->VolHdr.VolumeName, sizeof(VolumeName)); if (autochanger && !dir_get_volume_info(this, GET_VOL_INFO_FOR_READ)) { /* * If we get here, we know we cannot write on the Volume, * and we know that we cannot read it either, so it * is not in the autochanger. */ mark_volume_not_inchanger(); } dev->VolCatInfo = devVolCatInfo; /* structure assignment */ dev->set_unload(); /* unload this volume */ Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n" " Current Volume \"%s\" not acceptable because:\n" " %s"), dcrVolCatInfo.VolCatName, dev->VolHdr.VolumeName, vol_info_msg.c_str()); ask = true; /* Restore saved DCR before continuing */ bstrncpy(VolumeName, saveVolumeName, sizeof(VolumeName)); VolCatInfo = dcrVolCatInfo; /* structure assignment */ goto check_next_volume; } /* * This was not the volume we expected, but it is OK with * the Director, so use it. */ Dmsg1(150, "Got new Volume name=%s\n", VolumeName); dev->VolCatInfo = VolCatInfo; /* structure assignment */ Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName); if (reserve_volume(this, dev->VolHdr.VolumeName) == NULL) { Jmsg2(jcr, M_WARNING, 0, _("Could not reserve volume %s on %s\n"), dev->VolHdr.VolumeName, dev->print_name()); ask = true; goto check_next_volume; } break; /* got a Volume */ /* * At this point, we assume we have a blank tape mounted. */ case VOL_IO_ERROR: if (dev->is_dvd()) { Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg); mark_volume_in_error(); goto check_bail_out; /* we could not write on DVD */ } /* Fall through wanted */ case VOL_NO_LABEL: switch (try_autolabel(true)) { case try_next_vol: goto check_next_volume; case try_read_vol: goto check_read_volume; case try_error: goto check_bail_out; case try_default: break; } /* NOTE! Fall-through wanted. */ case VOL_NO_MEDIA: default: Dmsg0(200, "VOL_NO_MEDIA or default.\n"); /* Send error message */ if (!dev->poll) { } else { Dmsg1(200, "Msg suppressed by poll: %s\n", jcr->errmsg); } ask = true; /* Needed, so the medium can be changed */ if (dev->requires_mount()) { dev->close(); } goto check_next_volume; } return check_ok; check_next_volume: return check_next_vol; check_bail_out: return check_error; check_read_volume: return check_read_vol; }
/* * Write a Volume Label * !!! Note, this is ONLY used for writing * a fresh volume label. Any data * after the label will be destroyed, * in fact, we write the label 5 times !!!! * * This routine should be used only when labeling a blank tape. */ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName, bool relabel) { JCR *jcr = dcr->jcr; DEVICE *dev = dcr->dev; DEV_BLOCK *block = dcr->block; Dmsg0(150, "write_volume_label()\n"); if (*VolName == 0) { Pmsg0(0, "=== ERROR: write_new_volume_label_to_dev called with NULL VolName\n"); goto bail_out; } if (relabel) { volume_unused(dcr); /* mark current volume unused */ /* Truncate device */ if (!dev->truncate(dcr)) { goto bail_out; } if (!dev->is_tape()) { dev->close(dcr); /* make sure file closed for rename */ } } /* Set the new filename for open, ... */ dev->setVolCatName(VolName); dcr->setVolCatName(VolName); Dmsg1(150, "New VolName=%s\n", VolName); if (!dev->open(dcr, OPEN_READ_WRITE)) { /* If device is not tape, attempt to create it */ if (dev->is_tape() || !dev->open(dcr, CREATE_READ_WRITE)) { Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"), dev->print_name(), dcr->VolumeName, dev->bstrerror()); goto bail_out; } } Dmsg1(150, "Label type=%d\n", dev->label_type); /* * Let any stored plugin know that we are about to write a new label to the volume. */ if (generate_plugin_event(jcr, bsdEventLabelWrite, dcr) != bRC_OK) { Dmsg0(200, "Error from bsdEventLabelWrite plugin event.\n"); goto bail_out; } for ( ;; ) { empty_block(block); if (!dev->rewind(dcr)) { Dmsg2(130, "Bad status on %s from rewind: ERR=%s\n", dev->print_name(), dev->print_errmsg()); if (!forge_on) { goto bail_out; } } /* Temporarily mark in append state to enable writing */ dev->set_append(); /* Create PRE_LABEL */ create_volume_label(dev, VolName, PoolName); /* * If we have already detected an ANSI label, re-read it * to skip past it. Otherwise, we write a new one if * so requested. */ if (dev->label_type != B_BAREOS_LABEL) { if (read_ansi_ibm_label(dcr) != VOL_OK) { dev->rewind(dcr); goto bail_out; } } else if (!write_ansi_ibm_labels(dcr, ANSI_VOL_LABEL, VolName)) { goto bail_out; } create_volume_label_record(dcr, dev, dcr->rec); dcr->rec->Stream = 0; dcr->rec->maskedStream = 0; if (!write_record_to_block(dcr, dcr->rec)) { Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg()); goto bail_out; } else { Dmsg2(130, "Wrote label of %d bytes to %s\n", dcr->rec->data_len, dev->print_name()); } Dmsg0(130, "Call write_block_to_dev()\n"); if (!dcr->write_block_to_dev()) { Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg()); goto bail_out; } break; } dev = dcr->dev; Dmsg0(130, " Wrote block to device\n"); if (dev->weof(1)) { dev->set_labeled(); write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName); } if (debug_level >= 20) { dump_volume_label(dev); } Dmsg0(100, "Call reserve_volume\n"); if (reserve_volume(dcr, VolName) == NULL) { Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"), dev->VolHdr.VolumeName, dev->print_name()); Dmsg1(100, "%s", jcr->errmsg); goto bail_out; } dev = dcr->dev; /* may have changed in reserve_volume */ dev->clear_append(); /* remove append since this is PRE_LABEL */ return true; bail_out: volume_unused(dcr); dev->clear_volhdr(); dev->clear_append(); /* remove append since this is PRE_LABEL */ return false; }