2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Subroutines to handle Catalog reqests sent to the Director
21 * Reqests/commands from the Director are handled in dircmd.c
23 * Kern Sibbald, December 2000
26 #include "bacula.h" /* pull in global headers */
27 #include "stored.h" /* pull in Storage Deamon headers */
29 static const int dbglvl = 200;
31 /* Requests sent to the Director */
32 static char Find_media[] = "CatReq JobId=%ld FindMedia=%d pool_name=%s media_type=%s vol_type=%d\n";
33 static char Get_Vol_Info[] = "CatReq JobId=%ld GetVolInfo VolName=%s write=%d\n";
34 static char Update_media[] = "CatReq JobId=%ld UpdateMedia VolName=%s"
35 " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolABytes=%s"
36 " VolHoleBytes=%s VolHoles=%u VolMounts=%u"
37 " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
38 " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
39 " VolFirstWritten=%s VolType=%u VolParts=%d VolCloudParts=%d"
40 " LastPartBytes=%lld Enabled=%d\n";
41 static char Create_jobmedia[] = "CatReq JobId=%ld CreateJobMedia\n";
42 static char FileAttributes[] = "UpdCat JobId=%ld FileAttributes ";
44 /* Responses received from the Director */
45 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
46 " VolBlocks=%lu VolBytes=%lld VolABytes=%lld"
47 " VolHoleBytes=%lld VolHoles=%lu VolMounts=%lu"
48 " VolErrors=%lu VolWrites=%lu"
49 " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s"
50 " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
51 " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
52 " VolType=%lu LabelType=%ld MediaId=%lld ScratchPoolId=%lld"
53 " VolParts=%d VolCloudParts=%d LastPartBytes=%lld Enabled=%d\n";
56 static char OK_create[] = "1000 OK CreateJobMedia\n";
58 static bthread_mutex_t vol_info_mutex = BTHREAD_MUTEX_PRIORITY(PRIO_SD_VOL_INFO);
62 static char Device_update[] = "DevUpd JobId=%ld device=%s "
63 "append=%d read=%d num_writers=%d "
64 "open=%d labeled=%d offline=%d "
65 "reserved=%d max_writers=%d "
66 "autoselect=%d autochanger=%d "
68 "changer_name=%s media_type=%s volume_name=%s\n";
71 /** Send update information about a device to Director */
72 bool dir_update_device(JCR *jcr, DEVICE *dev)
74 BSOCK *dir = jcr->dir_bsock;
75 POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
76 DEVRES *device = dev->device;
79 pm_strcpy(dev_name, device->hdr.name);
80 bash_spaces(dev_name);
81 if (dev->is_labeled()) {
82 pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
84 pm_strcpy(VolumeName, "*");
86 bash_spaces(VolumeName);
87 pm_strcpy(MediaType, device->media_type);
88 bash_spaces(MediaType);
89 if (device->changer_res) {
90 pm_strcpy(ChangerName, device->changer_res->hdr.name);
91 bash_spaces(ChangerName);
93 pm_strcpy(ChangerName, "*");
95 ok = dir->fsend(Device_update,
99 dev->can_read()!=0, dev->num_writers,
100 dev->is_open()!=0, dev->is_labeled()!=0,
101 dev->is_offline()!=0, dev->reserved_device,
102 dev->is_tape()?100000:1,
105 ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
106 Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
110 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
112 BSOCK *dir = jcr->dir_bsock;
113 POOL_MEM dev_name, MediaType;
117 pm_strcpy(dev_name, changer->hdr.name);
118 bash_spaces(dev_name);
119 device = (DEVRES *)changer->device->first();
120 pm_strcpy(MediaType, device->media_type);
121 bash_spaces(MediaType);
122 /* This is mostly to indicate that we are here */
123 ok = dir->fsend(Device_update,
125 dev_name.c_str(), /* Changer name */
126 0, 0, 0, /* append, read, num_writers */
127 0, 0, 0, /* is_open, is_labeled, offline */
128 0, 0, /* reserved, max_writers */
131 changer->device->size(), /* Number of devices */
133 "*", /* ChangerName */
134 MediaType.c_str(), /* MediaType */
136 Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
142 static AskDirHandler *askdir_handler = NULL; /* must be true when inside a "btools" */
145 * btools must call this function, to modify behavior of some functions here
147 AskDirHandler *init_askdir_handler(AskDirHandler *new_askdir_handler)
149 AskDirHandler *old = askdir_handler;
150 askdir_handler = new_askdir_handler;
155 * Alternate function used by btools
157 bool AskDirHandler::dir_ask_sysop_to_mount_volume(DCR *dcr, bool /*writing*/)
159 DEVICE *dev = dcr->dev;
160 fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
161 dcr->VolumeName, dev->print_name());
167 bool AskDirHandler::dir_get_volume_info(DCR *dcr, const char *VolumeName, enum get_vol_info_rw writing)
169 Dmsg0(100, "Fake dir_get_volume_info\n");
170 dcr->setVolCatName(VolumeName);
171 Dmsg2(500, "Vol=%s VolType=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatType);
176 * Send current JobStatus to Director
178 bool dir_send_job_status(JCR *jcr)
180 if (askdir_handler) {
181 return askdir_handler->dir_send_job_status(jcr);
184 return jcr->sendJobStatus();
188 * Common routine for:
189 * dir_get_volume_info()
191 * dir_find_next_appendable_volume()
193 * NOTE!!! All calls to this routine must be protected by
194 * locking vol_info_mutex before calling it so that
195 * we don't have one thread modifying the parameters
196 * and another reading them.
198 * Returns: true on success and vol info in dcr->VolCatInfo
201 static bool do_get_volume_info(DCR *dcr)
204 BSOCK *dir = jcr->dir_bsock;
210 dcr->setVolCatInfo(false);
211 if (dir->recv() <= 0) {
212 Dmsg0(dbglvl, "getvolname error bnet_recv\n");
213 Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
216 memset(&vol, 0, sizeof(vol));
217 n = sscanf(dir->msg, OK_media, vol.VolCatName,
218 &vol.VolCatJobs, &vol.VolCatFiles,
219 &vol.VolCatBlocks, &vol.VolCatAmetaBytes,
220 &vol.VolCatAdataBytes, &vol.VolCatHoleBytes,
221 &vol.VolCatHoles, &vol.VolCatMounts, &vol.VolCatErrors,
222 &vol.VolCatWrites, &vol.VolCatMaxBytes,
223 &vol.VolCatCapacityBytes, vol.VolCatStatus,
224 &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
225 &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
226 &vol.EndFile, &vol.EndBlock, &vol.VolCatType,
227 &vol.LabelType, &vol.VolMediaId, &vol.VolScratchPoolId,
228 &vol.VolCatParts, &vol.VolCatCloudParts,
229 &vol.VolLastPartBytes, &Enabled);
230 Dmsg2(dbglvl, "<dird n=%d %s", n, dir->msg);
232 Dmsg1(dbglvl, "get_volume_info failed: ERR=%s", dir->msg);
234 * Note, we can get an error here either because there is
235 * a comm problem, or if the volume is not a suitable
236 * volume to use, so do not issue a Jmsg() here, do it
237 * in the calling routine.
239 Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
242 vol.InChanger = InChanger; /* bool in structure */
243 vol.VolEnabled = Enabled; /* bool in structure */
245 vol.VolCatBytes = vol.VolCatAmetaBytes + vol.VolCatAdataBytes;
246 unbash_spaces(vol.VolCatName);
247 bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
248 dcr->VolCatInfo = vol; /* structure assignment */
250 Dmsg3(dbglvl, "do_reqest_vol_info return true slot=%d Volume=%s MediaId=%lld\n",
251 dcr->VolCatInfo.Slot, dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolMediaId);
252 Dmsg5(dbglvl, "Dir returned VolCatAmetaBytes=%lld VolCatAdataBytes=%lld Status=%s Vol=%s MediaId=%lld\n",
253 dcr->VolCatInfo.VolCatAmetaBytes, dcr->VolCatInfo.VolCatAdataBytes,
254 dcr->VolCatInfo.VolCatStatus, dcr->VolCatInfo.VolCatName,
255 dcr->VolCatInfo.VolMediaId);
261 * Get Volume info for a specific volume from the Director's Database
263 * Returns: true on success (Director guarantees that Pool and MediaType
264 * are correct and VolStatus==Append or
265 * VolStatus==Recycle)
268 * Volume information returned in dcr->VolCatInfo
270 bool dir_get_volume_info(DCR *dcr,
271 const char *VolumeName,
272 enum get_vol_info_rw writing)
274 if (askdir_handler) {
275 return askdir_handler->dir_get_volume_info(dcr, VolumeName, writing);
279 BSOCK *dir = jcr->dir_bsock;
282 dcr->setVolCatName(VolumeName);
283 bash_spaces(dcr->getVolCatName());
284 dir->fsend(Get_Vol_Info, jcr->JobId, dcr->getVolCatName(),
285 writing==GET_VOL_INFO_FOR_WRITE?1:0);
286 Dmsg1(dbglvl, ">dird %s", dir->msg);
287 unbash_spaces(dcr->getVolCatName());
288 bool ok = do_get_volume_info(dcr);
296 * Get info on the next appendable volume in the Director's database
298 * Returns: true on success dcr->VolumeName is volume
299 * reserve_volume() called on Volume name
300 * false on failure dcr->VolumeName[0] == 0
301 * also sets dcr->found_in_use if at least one
302 * in use volume was found.
304 * Volume information returned in dcr
307 bool dir_find_next_appendable_volume(DCR *dcr)
309 /* SD tools setup a handler because they have no connection to Dir */
310 if (askdir_handler) {
311 return askdir_handler->dir_find_next_appendable_volume(dcr);
315 BSOCK *dir = jcr->dir_bsock;
317 char lastVolume[MAX_NAME_LENGTH];
319 Dmsg2(dbglvl, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n",
320 dcr->is_reserved(), dcr->VolumeName);
321 Mmsg(jcr->errmsg, "Unknown error\n");
324 * Try the thirty oldest or most available volumes. Note,
325 * the most available could already be mounted on another
326 * drive, so we continue looking for a not in use Volume.
330 dcr->clear_found_in_use();
332 for (int vol_index=1; vol_index < 30; vol_index++) {
333 bash_spaces(dcr->media_type);
334 bash_spaces(dcr->pool_name);
335 dir->fsend(Find_media, jcr->JobId, vol_index, dcr->pool_name, dcr->media_type,
337 unbash_spaces(dcr->media_type);
338 unbash_spaces(dcr->pool_name);
339 Dmsg1(dbglvl, ">dird %s", dir->msg);
340 if (do_get_volume_info(dcr)) {
341 /* Give up if we get the same volume name twice */
342 if (lastVolume[0] && strcmp(lastVolume, dcr->VolumeName) == 0) {
343 Mmsg(jcr->errmsg, "Director returned same volume name=%s twice.\n",
345 Dmsg1(dbglvl, "Got same vol = %s\n", lastVolume);
348 /* If VolCatAdataBytes, we have ALIGNED_DEV */
349 if (dcr->VolCatInfo.VolCatType == 0 && dcr->VolCatInfo.VolCatAdataBytes != 0) {
350 dcr->VolCatInfo.VolCatType = B_ALIGNED_DEV;
353 * If we have VolType and we are disk or aligned, the VolType must match
355 /* ***FIXME*** find better way to handle voltype */
356 if (dcr->VolCatInfo.VolCatType != 0 &&
357 (dcr->dev->dev_type == B_FILE_DEV || dcr->dev->dev_type == B_ALIGNED_DEV ||
358 dcr->dev->dev_type == B_CLOUD_DEV) &&
359 dcr->dev->dev_type != (int)dcr->VolCatInfo.VolCatType) {
360 Dmsg2(000, "Skip vol. Wanted VolType=%d Got=%d\n", dcr->dev->dev_type, dcr->VolCatInfo.VolCatType);
363 bstrncpy(lastVolume, dcr->VolumeName, sizeof(lastVolume));
364 if (dcr->can_i_write_volume()) {
365 Dmsg1(dbglvl, "Call reserve_volume for write. Vol=%s\n", dcr->VolumeName);
366 if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
367 Dmsg1(dbglvl, "%s", jcr->errmsg);
368 if (dcr->dev->must_wait()) {
370 dcr->VolumeName[0] = 0;
375 Dmsg1(dbglvl, "dir_find_next_appendable_volume return true. vol=%s\n",
380 Mmsg(jcr->errmsg, "Volume %s is in use.\n", dcr->VolumeName);
381 Dmsg1(dbglvl, "Volume %s is in use.\n", dcr->VolumeName);
382 /* If volume is not usable, it is in use by someone else */
383 dcr->set_found_in_use();
387 Dmsg2(dbglvl, "No vol. index %d return false. dev=%s\n", vol_index,
388 dcr->dev->print_name());
392 dcr->VolumeName[0] = 0;
397 if (!rtn && dcr->VolCatInfo.VolScratchPoolId != 0) {
398 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
399 Dmsg2(000, "!!!!!!!!! Volume=%s rejected ScratchPoolId=%lld\n", dcr->VolumeName,
400 dcr->VolCatInfo.VolScratchPoolId);
401 Dmsg1(000, "%s", jcr->errmsg);
403 // Dmsg3(000, "Rtn=%d Volume=%s ScratchPoolId=%lld\n", rtn, dcr->VolumeName,
404 // dcr->VolCatInfo.VolScratchPoolId);
411 * After writing a Volume, send the updated statistics
412 * back to the director. The information comes from the
415 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten,
418 if (askdir_handler) {
419 return askdir_handler->dir_update_volume_info(dcr, label, update_LastWritten, use_dcr);
423 BSOCK *dir = jcr->dir_bsock;
424 DEVICE *dev = dcr->ameta_dev;
426 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
431 /* If system job, do not update catalog, except if we explicitly force it. */
432 if (jcr->getJobType() == JT_SYSTEM &&
433 !dcr->force_update_volume_info) {
437 /* Lock during Volume update */
439 dev->Lock_VolCatInfo();
442 vol = dcr->VolCatInfo; /* structure assignment */
444 vol = dev->VolCatInfo; /* structure assignment */
447 /* This happens when nothing to update after fixup_device ... */
448 if (vol.VolCatName[0] == 0) {
451 Dmsg4(100, "Update cat VolBytes=%lld VolABytes=%lld Status=%s Vol=%s\n",
452 vol.VolCatAmetaBytes, vol.VolCatAdataBytes, vol.VolCatStatus, vol.VolCatName);
453 /* Just labeled or relabeled the tape */
455 dev->setVolCatStatus("Append");
457 // if (update_LastWritten) {
458 vol.VolLastWritten = time(NULL);
460 pm_strcpy(VolumeName, vol.VolCatName);
461 bash_spaces(VolumeName);
462 InChanger = vol.InChanger;
464 if (vol.VolCatHoleBytes > (((uint64_t)2)<<60)) {
465 Pmsg1(010, "VolCatHoleBytes too big: %lld. Reset to zero.\n",
466 vol.VolCatHoleBytes);
467 vol.VolCatHoleBytes = 0;
469 /* Set device type where this Volume used */
470 if (vol.VolCatType == 0) {
471 vol.VolCatType = dev->dev_type;
473 dir->fsend(Update_media, jcr->JobId,
474 VolumeName.c_str(), vol.VolCatJobs, vol.VolCatFiles,
475 vol.VolCatBlocks, edit_uint64(vol.VolCatAmetaBytes, ed1),
476 edit_uint64(vol.VolCatAdataBytes, ed2),
477 edit_uint64(vol.VolCatHoleBytes, ed3),
478 vol.VolCatHoles, vol.VolCatMounts, vol.VolCatErrors,
479 vol.VolCatWrites, edit_uint64(vol.VolCatMaxBytes, ed4),
480 edit_uint64(vol.VolLastWritten, ed5),
481 vol.VolCatStatus, vol.Slot, label,
482 InChanger, /* bool in structure */
483 edit_int64(vol.VolReadTime, ed6),
484 edit_int64(vol.VolWriteTime, ed7),
485 edit_uint64(vol.VolFirstWritten, ed8),
488 vol.VolCatCloudParts,
489 vol.VolLastPartBytes,
491 Dmsg1(100, ">dird %s", dir->msg);
493 /* Do not lock device here because it may be locked from label */
494 if (!jcr->is_canceled()) {
496 * We sent info directly from dev to the Director.
497 * What the Director sends back is first read into
498 * the dcr with do_get_volume_info()
500 if (!do_get_volume_info(dcr)) {
501 Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
502 Dmsg2(dbglvl, _("Didn't get vol info vol=%s: ERR=%s"),
503 vol.VolCatName, jcr->errmsg);
506 Dmsg1(100, "get_volume_info() %s", dir->msg);
508 /* Update dev Volume info in case something changed (e.g. expired) */
510 dcr->VolCatInfo.Slot = dev->VolCatInfo.Slot;
511 bstrncpy(dcr->VolCatInfo.VolCatStatus, dev->VolCatInfo.VolCatStatus, sizeof(vol.VolCatStatus));
512 dcr->VolCatInfo.VolCatAdataBytes = dev->VolCatInfo.VolCatAdataBytes;
513 dcr->VolCatInfo.VolCatAmetaBytes = dev->VolCatInfo.VolCatAmetaBytes;
514 dcr->VolCatInfo.VolCatHoleBytes = dev->VolCatInfo.VolCatHoleBytes;
515 dcr->VolCatInfo.VolCatHoles = dev->VolCatInfo.VolCatHoles;
516 dcr->VolCatInfo.VolCatPadding = dev->VolCatInfo.VolCatPadding;
517 dcr->VolCatInfo.VolCatAmetaPadding = dev->VolCatInfo.VolCatAmetaPadding;
518 dcr->VolCatInfo.VolCatAdataPadding = dev->VolCatInfo.VolCatAdataPadding;
519 dcr->VolCatInfo.VolCatFiles = dev->VolCatInfo.VolCatFiles;
520 dcr->VolCatInfo.VolCatBytes = dev->VolCatInfo.VolCatBytes;
521 dcr->VolCatInfo.VolCatMounts = dev->VolCatInfo.VolCatMounts;
522 dcr->VolCatInfo.VolCatJobs = dev->VolCatInfo.VolCatJobs;
523 dcr->VolCatInfo.VolCatFiles = dev->VolCatInfo.VolCatFiles;
524 dcr->VolCatInfo.VolCatRecycles = dev->VolCatInfo.VolCatRecycles;
525 dcr->VolCatInfo.VolCatWrites = dev->VolCatInfo.VolCatWrites;
526 dcr->VolCatInfo.VolCatReads = dev->VolCatInfo.VolCatReads;
532 dev->Unlock_VolCatInfo();
537 struct JOBMEDIA_ITEM {
542 uint32_t VolFirstIndex;
543 uint32_t VolLastIndex;
550 void create_jobmedia_queue(JCR *jcr)
552 JOBMEDIA_ITEM *item = NULL;
553 jcr->jobmedia_queue = New(dlist(item, &item->link));
556 bool flush_jobmedia_queue(JCR *jcr)
558 if (askdir_handler) {
559 return askdir_handler->flush_jobmedia_queue(jcr);
563 BSOCK *dir = jcr->dir_bsock;
566 if (!jcr->jobmedia_queue || jcr->jobmedia_queue->size() == 0) {
567 return true; /* should never happen */
569 Dmsg1(400, "=== Flush jobmedia queue = %d\n", jcr->jobmedia_queue->size());
571 dir->fsend(Create_jobmedia, jcr->JobId);
572 foreach_dlist(item, jcr->jobmedia_queue) {
573 ok = dir->fsend("%u %u %u %u %u %u %lld\n",
574 item->VolFirstIndex, item->VolLastIndex,
575 item->StartFile, item->EndFile,
576 item->StartBlock, item->EndBlock,
578 Dmsg2(400, "sd->dir: ok=%d Jobmedia=%s", ok, dir->msg);
580 dir->signal(BNET_EOD);
581 jcr->jobmedia_queue->destroy();
583 if (dir->recv() <= 0) {
584 Dmsg0(dbglvl, "create_jobmedia error bnet_recv\n");
585 Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia records: ERR=%s\n"),
589 Dmsg1(210, "<dird %s", dir->msg);
590 if (strcmp(dir->msg, OK_create) != 0) {
591 Dmsg1(dbglvl, "Bad response from Dir: %s\n", dir->msg);
592 Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia records: %s\n"), dir->msg);
600 * After writing a Volume, create the JobMedia record.
602 bool dir_create_jobmedia_record(DCR *dcr, bool zero)
604 if (askdir_handler) {
605 return askdir_handler->dir_create_jobmedia_record(dcr, zero);
609 BSOCK *dir = jcr->dir_bsock;
613 if (!zero && !dcr->WroteVol) {
616 if (!zero && dcr->VolLastIndex == 0) {
617 Pmsg7(0/*dbglvl*/, "Discard: JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
618 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
619 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
620 return true; /* nothing written to the Volume */
622 /* Throw out records where the start address is bigger than the end */
623 if (!zero && dcr->StartAddr > dcr->EndAddr) {
624 Pmsg7(0/*dbglvl*/, "Discard: JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
625 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
626 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
630 /* If system job, do not update catalog */
631 if (jcr->getJobType() == JT_SYSTEM) {
635 /* Throw out records where FI is zero -- i.e. nothing done */
636 if (!zero && dcr->VolFirstIndex == 0 &&
637 (dcr->StartAddr != 0 || dcr->EndAddr != 0)) {
638 Pmsg7(0/*dbglvl*/, "Discard: JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
639 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
640 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
645 * If this Job is incomplete, we need to backup the FileIndex
646 * to the last correctly saved file so that the JobMedia
647 * LastIndex is correct.
649 * Note: ***FIXME*** though it is not required, we probably
650 * should also keep a last EndFile and last EndBlock and
651 * reset them correctly too so that the JobMedia record is
654 if (jcr->is_JobStatus(JS_Incomplete)) {
655 dcr->VolLastIndex = dir->get_lastFileIndex();
656 Dmsg1(100, "======= Set FI=%ld\n", dcr->VolLastIndex);
659 Dmsg7(100, "Queue JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
660 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
661 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
662 item = (JOBMEDIA_ITEM *)malloc(sizeof(JOBMEDIA_ITEM));
664 item->VolFirstIndex = item->VolLastIndex = 0;
665 item->StartFile = item->EndFile = 0;
666 item->StartBlock = item->EndBlock = 0;
667 item->StartAddr = item->EndAddr = 0;
668 item->VolMediaId = dcr->VolMediaId;
670 item->VolFirstIndex = dcr->VolFirstIndex;
671 item->VolLastIndex = dcr->VolLastIndex;
672 item->StartFile = (uint32_t)(dcr->StartAddr >> 32);
673 item->EndFile = (uint32_t)(dcr->EndAddr >> 32);
674 item->StartBlock = (uint32_t)dcr->StartAddr;
675 item->EndBlock = (uint32_t)dcr->EndAddr;
676 item->StartAddr = dcr->StartAddr;
677 item->EndAddr = dcr->EndAddr;
678 item->VolMediaId = dcr->VolMediaId;
680 jcr->jobmedia_queue->append(item);
681 /* Flush at 100 queue size of 100 jobmedia records */
682 if (zero || jcr->jobmedia_queue->size() >= 100) {
683 ok = flush_jobmedia_queue(jcr);
686 dcr->VolFirstIndex = dcr->VolLastIndex = 0;
687 dcr->StartAddr = dcr->EndAddr = 0;
689 dcr->WroteVol = false;
694 * Update File Attribute data
695 * We do the following:
696 * 1. expand the bsock buffer to be large enough
697 * 2. Write a "header" into the buffer with serialized data
702 * data length that follows
703 * start of raw byte data from the Device record.
704 * Note, this is primarily for Attribute data, but can
705 * also handle any device record. The Director must know
706 * the raw byte data format that is defined for each Stream.
707 * Now Restore Objects pass through here STREAM_RESTORE_OBJECT
709 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
711 if (askdir_handler) {
712 return askdir_handler->dir_update_file_attributes(dcr, rec);
716 BSOCK *dir = jcr->dir_bsock;
719 #ifdef NO_ATTRIBUTES_TEST
723 dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
724 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
725 dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
726 MAX_NAME_LENGTH + 1, FileAttributes, jcr->JobId);
727 ser_begin(dir->msg + dir->msglen, 0);
728 ser_uint32(rec->VolSessionId);
729 ser_uint32(rec->VolSessionTime);
730 ser_int32(rec->FileIndex);
731 ser_int32(rec->Stream);
732 ser_uint32(rec->data_len);
733 ser_bytes(rec->data, rec->data_len);
734 dir->msglen = ser_length(dir->msg);
735 Dmsg1(1800, ">dird %s\n", dir->msg); /* Attributes */
736 if (rec->maskedStream == STREAM_UNIX_ATTRIBUTES ||
737 rec->maskedStream == STREAM_UNIX_ATTRIBUTES_EX) {
738 Dmsg2(1500, "==== set_data_end FI=%ld %s\n", rec->FileIndex, rec->data);
739 dir->set_data_end(rec->FileIndex); /* set offset of valid data */
746 * Request the sysop to create an appendable volume
748 * Entered with device blocked.
749 * Leaves with device blocked.
751 * Returns: true on success (operator issues a mount command)
753 * Note, must create dev->errmsg on error return.
755 * On success, dcr->VolumeName and dcr->VolCatInfo contain
756 * information on suggested volume, but this may not be the
757 * same as what is actually mounted.
759 * When we return with success, the correct tape may or may not
760 * actually be mounted. The calling routine must read it and
763 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
765 if (askdir_handler) {
766 return askdir_handler->dir_ask_sysop_to_create_appendable_volume(dcr);
769 int stat = W_TIMEOUT;
770 DEVICE *dev = dcr->dev;
772 bool got_vol = false;
774 if (job_canceled(jcr)) {
778 Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
779 ASSERT(dev->blocked());
781 if (job_canceled(jcr)) {
783 _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
784 jcr->Job, dev->print_name());
785 Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
789 got_vol = dir_find_next_appendable_volume(dcr); /* get suggested volume */
794 if (stat == W_TIMEOUT || stat == W_MOUNT) {
796 "Job %s is waiting. Cannot find any appendable volumes.\n"
797 "Please use the \"label\" command to create a new Volume for:\n"
800 " Media type: %s\n"),
805 Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
806 Dmsg1(dbglvl, "%s", dev->errmsg);
810 jcr->sendJobStatus(JS_WaitMedia);
812 stat = wait_for_sysop(dcr);
813 Dmsg1(dbglvl, "Back from wait_for_sysop stat=%d\n", stat);
815 Dmsg1(dbglvl, "Poll timeout in create append vol on device %s\n", dev->print_name());
819 if (stat == W_TIMEOUT) {
820 if (!double_dev_wait_time(dev)) {
821 Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
822 dev->print_name(), jcr->Job);
823 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
824 Dmsg1(dbglvl, "Gave up waiting on device %s\n", dev->print_name());
826 return false; /* exceeded maximum waits */
830 if (stat == W_ERROR) {
832 Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
833 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
837 Dmsg1(dbglvl, "Someone woke me for device %s\n", dev->print_name());
841 jcr->sendJobStatus(JS_Running);
842 Dmsg0(dbglvl, "leave dir_ask_sysop_to_create_appendable_volume\n");
847 * Request to mount specific Volume
849 * Entered with device blocked and dcr->VolumeName is desired
851 * Leaves with device blocked.
853 * Returns: true on success (operator issues a mount command)
855 * Note, must create dev->errmsg on error return.
858 bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool write_access)
860 if (askdir_handler) {
861 return askdir_handler->dir_ask_sysop_to_mount_volume(dcr, write_access);
864 int stat = W_TIMEOUT;
865 DEVICE *dev = dcr->dev;
868 Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
869 if (!dcr->VolumeName[0]) {
870 Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
875 if (dcr->no_mount_request) {
876 Mmsg(dev->errmsg, _("The current operation doesn't support mount request\n"));
882 if (job_canceled(jcr)) {
884 _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
885 jcr->Job, dev->print_name());
886 Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
891 * If we are not polling, and the wait timeout or the
892 * user explicitly did a mount, send him the message.
895 if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
898 msg = _("%sPlease mount append Volume \"%s\" or label a new one for:\n"
902 " Media type: %s\n");
904 msg = _("%sPlease mount read Volume \"%s\" for:\n"
908 " Media type: %s\n");
910 Jmsg(jcr, M_MOUNT, 0, msg,
911 dev->is_nospace()?_("\n\nWARNING: device is full! Please add more disk space then ...\n\n"):"",
917 Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
918 dcr->VolumeName, dev->print_name(), jcr->Job);
921 jcr->sendJobStatus(JS_WaitMount);
923 stat = wait_for_sysop(dcr); /* wait on device */
924 Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
926 Dmsg1(100, "Poll timeout in mount vol on device %s\n", dev->print_name());
927 Dmsg1(100, "Blocked=%s\n", dev->print_blocked());
931 if (stat == W_TIMEOUT) {
932 if (!double_dev_wait_time(dev)) {
933 Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
934 dev->print_name(), jcr->Job);
935 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
936 Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
938 return false; /* exceeded maximum waits */
942 if (stat == W_ERROR) {
944 Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
945 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
949 Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
954 if (job_canceled(jcr)) {
955 Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
956 jcr->Job, dev->print_name());
961 jcr->sendJobStatus(JS_Running);
962 Dmsg0(100, "leave dir_ask_sysop_to_mount_volume\n");