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
27 #include "bacula.h" /* pull in global headers */
28 #include "stored.h" /* pull in Storage Deamon headers */
30 static const int dbglvl = 200;
32 /* Requests sent to the Director */
33 static char Find_media[] = "CatReq Job=%s FindMedia=%d pool_name=%s media_type=%s vol_type=%d\n";
34 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
35 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
36 " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolABytes=%s"
37 " VolHoleBytes=%s VolHoles=%u VolMounts=%u"
38 " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
39 " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
40 " VolFirstWritten=%s VolType=%u\n";
41 static char Create_jobmedia[] = "CatReq Job=%s CreateJobMedia\n";
42 static char FileAttributes[] = "UpdCat Job=%s 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\n";
55 static char OK_create[] = "1000 OK CreateJobMedia\n";
57 static bthread_mutex_t vol_info_mutex = BTHREAD_MUTEX_PRIORITY(PRIO_SD_VOL_INFO);
61 static char Device_update[] = "DevUpd Job=%s device=%s "
62 "append=%d read=%d num_writers=%d "
63 "open=%d labeled=%d offline=%d "
64 "reserved=%d max_writers=%d "
65 "autoselect=%d autochanger=%d "
67 "changer_name=%s media_type=%s volume_name=%s\n";
70 /** Send update information about a device to Director */
71 bool dir_update_device(JCR *jcr, DEVICE *dev)
73 BSOCK *dir = jcr->dir_bsock;
74 POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
75 DEVRES *device = dev->device;
78 pm_strcpy(dev_name, device->hdr.name);
79 bash_spaces(dev_name);
80 if (dev->is_labeled()) {
81 pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
83 pm_strcpy(VolumeName, "*");
85 bash_spaces(VolumeName);
86 pm_strcpy(MediaType, device->media_type);
87 bash_spaces(MediaType);
88 if (device->changer_res) {
89 pm_strcpy(ChangerName, device->changer_res->hdr.name);
90 bash_spaces(ChangerName);
92 pm_strcpy(ChangerName, "*");
94 ok = dir->fsend(Device_update,
98 dev->can_read()!=0, dev->num_writers,
99 dev->is_open()!=0, dev->is_labeled()!=0,
100 dev->is_offline()!=0, dev->reserved_device,
101 dev->is_tape()?100000:1,
104 ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
105 Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
109 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
111 BSOCK *dir = jcr->dir_bsock;
112 POOL_MEM dev_name, MediaType;
116 pm_strcpy(dev_name, changer->hdr.name);
117 bash_spaces(dev_name);
118 device = (DEVRES *)changer->device->first();
119 pm_strcpy(MediaType, device->media_type);
120 bash_spaces(MediaType);
121 /* This is mostly to indicate that we are here */
122 ok = dir->fsend(Device_update,
124 dev_name.c_str(), /* Changer name */
125 0, 0, 0, /* append, read, num_writers */
126 0, 0, 0, /* is_open, is_labeled, offline */
127 0, 0, /* reserved, max_writers */
130 changer->device->size(), /* Number of devices */
132 "*", /* ChangerName */
133 MediaType.c_str(), /* MediaType */
135 Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
142 * Send current JobStatus to Director
144 bool dir_send_job_status(JCR *jcr)
146 return jcr->sendJobStatus();
150 * Common routine for:
151 * dir_get_volume_info()
153 * dir_find_next_appendable_volume()
155 * NOTE!!! All calls to this routine must be protected by
156 * locking vol_info_mutex before calling it so that
157 * we don't have one thread modifying the parameters
158 * and another reading them.
160 * Returns: true on success and vol info in dcr->VolCatInfo
163 static bool do_get_volume_info(DCR *dcr)
166 BSOCK *dir = jcr->dir_bsock;
171 dcr->setVolCatInfo(false);
172 if (dir->recv() <= 0) {
173 Dmsg0(dbglvl, "getvolname error bnet_recv\n");
174 Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
177 memset(&vol, 0, sizeof(vol));
178 Dmsg1(dbglvl, "<dird %s", dir->msg);
179 n = sscanf(dir->msg, OK_media, vol.VolCatName,
180 &vol.VolCatJobs, &vol.VolCatFiles,
181 &vol.VolCatBlocks, &vol.VolCatAmetaBytes,
182 &vol.VolCatAdataBytes, &vol.VolCatHoleBytes,
183 &vol.VolCatHoles, &vol.VolCatMounts, &vol.VolCatErrors,
184 &vol.VolCatWrites, &vol.VolCatMaxBytes,
185 &vol.VolCatCapacityBytes, vol.VolCatStatus,
186 &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
187 &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
188 &vol.EndFile, &vol.EndBlock, &vol.VolCatType,
189 &vol.LabelType, &vol.VolMediaId, &vol.VolScratchPoolId);
191 Dmsg1(dbglvl, "get_volume_info failed: ERR=%s", dir->msg);
193 * Note, we can get an error here either because there is
194 * a comm problem, or if the volume is not a suitable
195 * volume to use, so do not issue a Jmsg() here, do it
196 * in the calling routine.
198 Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
201 vol.InChanger = InChanger; /* bool in structure */
203 vol.VolCatBytes = vol.VolCatAmetaBytes;
204 unbash_spaces(vol.VolCatName);
205 bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
206 dcr->VolCatInfo = vol; /* structure assignment */
208 Dmsg2(dbglvl, "do_reqest_vol_info return true slot=%d Volume=%s\n",
209 vol.Slot, vol.VolCatName);
210 Dmsg3(dbglvl, "Dir returned VolCatAmetaBytes=%lld Status=%s Vol=%s\n",
211 vol.VolCatAmetaBytes,
212 vol.VolCatStatus, vol.VolCatName);
218 * Get Volume info for a specific volume from the Director's Database
220 * Returns: true on success (Director guarantees that Pool and MediaType
221 * are correct and VolStatus==Append or
222 * VolStatus==Recycle)
225 * Volume information returned in dcr->VolCatInfo
227 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
230 BSOCK *dir = jcr->dir_bsock;
233 dcr->setVolCatName(dcr->VolumeName);
234 bash_spaces(dcr->getVolCatName());
235 dir->fsend(Get_Vol_Info, jcr->Job, dcr->getVolCatName(),
236 writing==GET_VOL_INFO_FOR_WRITE?1:0);
237 Dmsg1(dbglvl, ">dird %s", dir->msg);
238 unbash_spaces(dcr->getVolCatName());
239 bool ok = do_get_volume_info(dcr);
247 * Get info on the next appendable volume in the Director's database
249 * Returns: true on success dcr->VolumeName is volume
250 * reserve_volume() called on Volume name
251 * false on failure dcr->VolumeName[0] == 0
252 * also sets dcr->found_in_use if at least one
253 * in use volume was found.
255 * Volume information returned in dcr
258 bool dir_find_next_appendable_volume(DCR *dcr)
261 BSOCK *dir = jcr->dir_bsock;
263 char lastVolume[MAX_NAME_LENGTH];
265 Dmsg2(dbglvl, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n",
266 dcr->is_reserved(), dcr->VolumeName);
267 Mmsg(jcr->errmsg, "Unknown error\n");
270 * Try the thirty oldest or most available volumes. Note,
271 * the most available could already be mounted on another
272 * drive, so we continue looking for a not in use Volume.
276 dcr->clear_found_in_use();
278 for (int vol_index=1; vol_index < 30; vol_index++) {
279 bash_spaces(dcr->media_type);
280 bash_spaces(dcr->pool_name);
281 dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type,
283 unbash_spaces(dcr->media_type);
284 unbash_spaces(dcr->pool_name);
285 Dmsg1(dbglvl, ">dird %s", dir->msg);
286 if (do_get_volume_info(dcr)) {
287 /* Give up if we get the same volume name twice */
288 if (lastVolume[0] && strcmp(lastVolume, dcr->VolumeName) == 0) {
289 Mmsg(jcr->errmsg, "Director returned same volume name=%s twice.\n",
291 Dmsg1(dbglvl, "Got same vol = %s\n", lastVolume);
295 * If we have VolType and we are disk or ameta, the VolType must match
297 if (dcr->VolCatInfo.VolCatType != 0 &&
298 (dcr->dev->dev_type == B_FILE_DEV) &&
299 dcr->dev->dev_type != (int)dcr->VolCatInfo.VolCatType) {
300 Dmsg2(000, "Skip vol. Wanted VolType=%d Got=%d\n", dcr->dev->dev_type, dcr->VolCatInfo.VolCatType);
303 bstrncpy(lastVolume, dcr->VolumeName, sizeof(lastVolume));
304 if (dcr->can_i_write_volume()) {
305 Dmsg1(dbglvl, "Call reserve_volume for write. Vol=%s\n", dcr->VolumeName);
306 if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
307 Dmsg1(dbglvl, "%s", jcr->errmsg);
308 if (dcr->dev->must_wait()) {
310 dcr->VolumeName[0] = 0;
315 Dmsg1(dbglvl, "dir_find_next_appendable_volume return true. vol=%s\n",
320 Mmsg(jcr->errmsg, "Volume %s is in use.\n", dcr->VolumeName);
321 Dmsg1(dbglvl, "Volume %s is in use.\n", dcr->VolumeName);
322 /* If volume is not usable, it is in use by someone else */
323 dcr->set_found_in_use();
327 Dmsg2(dbglvl, "No vol. index %d return false. dev=%s\n", vol_index,
328 dcr->dev->print_name());
332 dcr->VolumeName[0] = 0;
337 if (!rtn && dcr->VolCatInfo.VolScratchPoolId != 0) {
338 Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
339 Dmsg2(000, "!!!!!!!!! Volume=%s rejected ScratchPoolId=%lld\n", dcr->VolumeName,
340 dcr->VolCatInfo.VolScratchPoolId);
341 Dmsg1(000, "%s", jcr->errmsg);
343 // Dmsg3(000, "Rtn=%d Volume=%s ScratchPoolId=%lld\n", rtn, dcr->VolumeName,
344 // dcr->VolCatInfo.VolScratchPoolId);
351 * After writing a Volume, send the updated statistics
352 * back to the director. The information comes from the
355 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
358 BSOCK *dir = jcr->dir_bsock;
359 DEVICE *dev = dcr->ameta_dev;
360 VOLUME_CAT_INFO *vol;
361 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
366 /* If system job, do not update catalog */
367 if (jcr->getJobType() == JT_SYSTEM) {
371 vol = &dev->VolCatInfo;
372 if (vol->VolCatName[0] == 0) {
373 Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
374 Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
378 /* Lock during Volume update */
380 dev->Lock_VolCatInfo();
381 Dmsg3(100, "Update cat VolBytes=%lld Status=%s Vol=%s\n",
382 vol->VolCatAmetaBytes, vol->VolCatStatus, vol->VolCatName);
383 /* Just labeled or relabeled the tape */
385 dev->setVolCatStatus("Append");
387 // if (update_LastWritten) {
388 vol->VolLastWritten = time(NULL);
390 pm_strcpy(VolumeName, vol->VolCatName);
391 bash_spaces(VolumeName);
392 InChanger = vol->InChanger;
393 vol->VolCatHoleBytes = 0;
395 /* Set device type where this Volume used */
396 if (vol->VolCatType == 0) {
397 vol->VolCatType = dev->dev_type;
399 dir->fsend(Update_media, jcr->Job,
400 VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
401 vol->VolCatBlocks, edit_uint64(vol->VolCatAmetaBytes, ed1),
402 edit_uint64(vol->VolCatAdataBytes, ed2),
403 edit_uint64(vol->VolCatHoleBytes, ed3),
404 vol->VolCatHoles, vol->VolCatMounts, vol->VolCatErrors,
405 vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed4),
406 edit_uint64(vol->VolLastWritten, ed5),
407 vol->VolCatStatus, vol->Slot, label,
408 InChanger, /* bool in structure */
409 edit_int64(vol->VolReadTime, ed6),
410 edit_int64(vol->VolWriteTime, ed7),
411 edit_uint64(vol->VolFirstWritten, ed8),
413 Dmsg1(100, ">dird %s", dir->msg);
415 /* Do not lock device here because it may be locked from label */
416 if (!jcr->is_canceled()) {
418 * We sent info directly from dev to the Director.
419 * What the Director sends back is first read into
420 * the dcr with do_get_volume_info()
422 if (!do_get_volume_info(dcr)) {
423 Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
424 Dmsg2(dbglvl, _("Didn't get vol info vol=%s: ERR=%s"),
425 vol->VolCatName, jcr->errmsg);
428 Dmsg1(100, "get_volume_info() %s", dir->msg);
429 /* Update dev Volume info in case something changed (e.g. expired) */
430 vol->Slot = dev->VolCatInfo.Slot;
431 bstrncpy(vol->VolCatStatus, dcr->VolCatInfo.VolCatStatus, sizeof(vol->VolCatStatus));
433 dcr->VolCatInfo.VolCatAdataBytes = dev->VolCatInfo.VolCatAdataBytes;
434 dcr->VolCatInfo.VolCatAmetaBytes = dev->VolCatInfo.VolCatAmetaBytes;
435 dcr->VolCatInfo.VolCatHoleBytes = dev->VolCatInfo.VolCatHoleBytes;
436 dcr->VolCatInfo.VolCatHoles = dev->VolCatInfo.VolCatHoles;
437 dcr->VolCatInfo.VolCatPadding = dev->VolCatInfo.VolCatPadding;
438 dcr->VolCatInfo.VolCatAmetaPadding = dev->VolCatInfo.VolCatAmetaPadding;
439 dcr->VolCatInfo.VolCatAdataPadding = dev->VolCatInfo.VolCatAdataPadding;
440 dcr->VolCatInfo.VolCatFiles = dev->VolCatInfo.VolCatFiles;
441 dcr->VolCatInfo.VolCatBytes = dev->VolCatInfo.VolCatBytes;
442 dcr->VolCatInfo.VolCatMounts = dev->VolCatInfo.VolCatMounts;
443 dcr->VolCatInfo.VolCatJobs = dev->VolCatInfo.VolCatJobs;
444 dcr->VolCatInfo.VolCatFiles = dev->VolCatInfo.VolCatFiles;
445 dcr->VolCatInfo.VolCatRecycles = dev->VolCatInfo.VolCatRecycles;
446 dcr->VolCatInfo.VolCatWrites = dev->VolCatInfo.VolCatWrites;
447 dcr->VolCatInfo.VolCatReads = dev->VolCatInfo.VolCatReads;
452 dev->Unlock_VolCatInfo();
457 struct JOBMEDIA_ITEM {
459 uint32_t VolFirstIndex;
460 uint32_t VolLastIndex;
468 void create_jobmedia_queue(JCR *jcr)
470 JOBMEDIA_ITEM *item = NULL;
471 jcr->jobmedia_queue = New(dlist(item, &item->link));
474 bool flush_jobmedia_queue(JCR *jcr)
477 BSOCK *dir = jcr->dir_bsock;
480 if (!jcr->jobmedia_queue || jcr->jobmedia_queue->size() == 0) {
481 //Dmsg0(000, "No jobmedia_queue\n");
482 return true; /* should never happen */
484 Dmsg1(400, "=== Flush jobmedia queue = %d\n", jcr->jobmedia_queue->size());
486 dir->fsend(Create_jobmedia, jcr->Job);
487 foreach_dlist(item, jcr->jobmedia_queue) {
488 ok = dir->fsend("%u %u %u %u %u %u %lld\n",
489 item->VolFirstIndex, item->VolLastIndex,
490 item->StartFile, item->EndFile,
491 item->StartBlock, item->EndBlock,
493 Dmsg2(400, "sd->dir: ok=%d Jobmedia=%s", ok, dir->msg);
495 dir->signal(BNET_EOD);
496 jcr->jobmedia_queue->destroy();
498 if (dir->recv() <= 0) {
499 Dmsg0(dbglvl, "create_jobmedia error bnet_recv\n");
500 Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia records: ERR=%s\n"),
504 Dmsg1(210, "<dird %s", dir->msg);
505 if (strcmp(dir->msg, OK_create) != 0) {
506 Dmsg1(dbglvl, "Bad response from Dir: %s\n", dir->msg);
507 Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia records: %s\n"), dir->msg);
514 * After writing a Volume, create the JobMedia record.
516 bool dir_create_jobmedia_record(DCR *dcr, bool zero)
519 BSOCK *dir = jcr->dir_bsock;
523 if (!zero && !dcr->WroteVol) {
526 if (!zero && dcr->VolLastIndex == 0) {
527 Dmsg7(dbglvl, "JobMedia Vol=%s wrote=%d MediaId=%d FI=%d LI=%d StartBlock=%d EndBlock=%d Suppressed\n",
528 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
529 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartBlock, dcr->EndBlock);
530 return true; /* nothing written to the Volume */
532 if (!zero && dcr->StartFile == dcr->EndFile && dcr->EndBlock < dcr->StartBlock) {
533 Dmsg7(dbglvl, "JobMedia Vol=%s wrote=%d MediaId=%d FI=%d LI=%d StartBlock=%d EndBlock=%d Suppressed\n",
534 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
535 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartBlock, dcr->EndBlock);
539 /* If system job, do not update catalog */
540 if (jcr->getJobType() == JT_SYSTEM) {
544 /* Throw out records where FI is zero -- i.e. nothing done */
545 if (!zero && dcr->VolFirstIndex == 0 &&
546 (dcr->StartBlock != 0 || dcr->EndBlock != 0)) {
547 Dmsg7(dbglvl, "Discard: JobMedia Vol=%s wrote=%d MediaId=%d FI=%d LI=%d StartBlock=%d EndBlock=%d Suppressed\n",
548 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
549 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartBlock, dcr->EndBlock);
554 * If this Job is incomplete, we need to backup the FileIndex
555 * to the last correctly saved file so that the JobMedia
556 * LastIndex is correct.
558 * Note: ***FIXME*** though it is not required, we probably
559 * should also keep a last EndFile and last EndBlock and
560 * reset them correctly too so that the JobMedia record is
563 if (jcr->is_JobStatus(JS_Incomplete)) {
564 dcr->VolLastIndex = dir->get_lastFileIndex();
565 Dmsg1(100, "======= Set FI=%ld\n", dcr->VolLastIndex);
568 Dmsg7(100, "JobMedia Vol=%s wrote=%d MediaId=%d FI=%d LI=%d StartBlock=%d EndBlock=%d Wrote\n",
569 dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
570 dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartBlock, dcr->EndBlock);
571 dcr->WroteVol = false;
572 item = (JOBMEDIA_ITEM *)malloc(sizeof(JOBMEDIA_ITEM));
574 item->VolFirstIndex = item->VolLastIndex = 0;
575 item->StartFile = item->EndFile = 0;
576 item->StartBlock = item->EndBlock = 0;
577 item->VolMediaId = dcr->VolMediaId;
579 item->VolFirstIndex = dcr->VolFirstIndex;
580 item->VolLastIndex = dcr->VolLastIndex;
581 item->StartFile = dcr->StartFile;
582 item->EndFile = dcr->EndFile;
583 item->StartBlock = dcr->StartBlock;
584 item->EndBlock = dcr->EndBlock;
585 item->VolMediaId = dcr->VolMediaId;
587 jcr->jobmedia_queue->append(item);
588 /* Flush at 100 queue size of 100 jobmedia records */
589 if (zero || jcr->jobmedia_queue->size() >= 100) {
590 ok = flush_jobmedia_queue(jcr);
593 dcr->VolFirstIndex = dcr->VolLastIndex = 0;
594 dcr->StartFile = dcr->EndFile = 0;
595 dcr->StartBlock = dcr->EndBlock = 0;
601 * Update File Attribute data
602 * We do the following:
603 * 1. expand the bsock buffer to be large enough
604 * 2. Write a "header" into the buffer with serialized data
609 * data length that follows
610 * start of raw byte data from the Device record.
611 * Note, this is primarily for Attribute data, but can
612 * also handle any device record. The Director must know
613 * the raw byte data format that is defined for each Stream.
614 * Now Restore Objects pass through here STREAM_RESTORE_OBJECT
616 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
619 BSOCK *dir = jcr->dir_bsock;
622 #ifdef NO_ATTRIBUTES_TEST
626 dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
627 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
628 dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
629 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
630 ser_begin(dir->msg + dir->msglen, 0);
631 ser_uint32(rec->VolSessionId);
632 ser_uint32(rec->VolSessionTime);
633 ser_int32(rec->FileIndex);
634 ser_int32(rec->Stream);
635 ser_uint32(rec->data_len);
636 ser_bytes(rec->data, rec->data_len);
637 dir->msglen = ser_length(dir->msg);
638 Dmsg1(1800, ">dird %s\n", dir->msg); /* Attributes */
639 if (rec->maskedStream == STREAM_UNIX_ATTRIBUTES ||
640 rec->maskedStream == STREAM_UNIX_ATTRIBUTES_EX) {
641 Dmsg2(1500, "==== set_data_end FI=%ld %s\n", rec->FileIndex, rec->data);
642 dir->set_data_end(rec->FileIndex); /* set offset of valid data */
649 * Request the sysop to create an appendable volume
651 * Entered with device blocked.
652 * Leaves with device blocked.
654 * Returns: true on success (operator issues a mount command)
656 * Note, must create dev->errmsg on error return.
658 * On success, dcr->VolumeName and dcr->VolCatInfo contain
659 * information on suggested volume, but this may not be the
660 * same as what is actually mounted.
662 * When we return with success, the correct tape may or may not
663 * actually be mounted. The calling routine must read it and
666 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
668 int stat = W_TIMEOUT;
669 DEVICE *dev = dcr->dev;
671 bool got_vol = false;
673 if (job_canceled(jcr)) {
677 Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
678 ASSERT(dev->blocked());
680 if (job_canceled(jcr)) {
682 _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
683 jcr->Job, dev->print_name());
684 Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
688 got_vol = dir_find_next_appendable_volume(dcr); /* get suggested volume */
693 if (stat == W_TIMEOUT || stat == W_MOUNT) {
695 "Job %s is waiting. Cannot find any appendable volumes.\n"
696 "Please use the \"label\" command to create a new Volume for:\n"
699 " Media type: %s\n"),
704 Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
705 Dmsg1(dbglvl, "%s", dev->errmsg);
709 jcr->sendJobStatus(JS_WaitMedia);
711 stat = wait_for_sysop(dcr);
712 Dmsg1(dbglvl, "Back from wait_for_sysop stat=%d\n", stat);
714 Dmsg1(dbglvl, "Poll timeout in create append vol on device %s\n", dev->print_name());
718 if (stat == W_TIMEOUT) {
719 if (!double_dev_wait_time(dev)) {
720 Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
721 dev->print_name(), jcr->Job);
722 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
723 Dmsg1(dbglvl, "Gave up waiting on device %s\n", dev->print_name());
725 return false; /* exceeded maximum waits */
729 if (stat == W_ERROR) {
731 Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
732 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
736 Dmsg1(dbglvl, "Someone woke me for device %s\n", dev->print_name());
741 jcr->sendJobStatus(JS_Running);
742 Dmsg0(dbglvl, "leave dir_ask_sysop_to_create_appendable_volume\n");
747 * Request to mount specific Volume
749 * Entered with device blocked and dcr->VolumeName is desired
751 * Leaves with device blocked.
753 * Returns: true on success (operator issues a mount command)
755 * Note, must create dev->errmsg on error return.
758 bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool write_access)
760 int stat = W_TIMEOUT;
761 DEVICE *dev = dcr->dev;
764 Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
765 if (!dcr->VolumeName[0]) {
766 Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
771 if (dcr->no_mount_request) {
772 Mmsg(dev->errmsg, _("The current operation doesn't support mount request\n"));
778 if (job_canceled(jcr)) {
779 Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
780 jcr->Job, dev->print_name());
790 * If we are not polling, and the wait timeout or the
791 * user explicitly did a mount, send him the message.
794 if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
797 msg = _("%sPlease mount append Volume \"%s\" or label a new one for:\n"
801 " Media type: %s\n");
803 msg = _("%sPlease mount read Volume \"%s\" for:\n"
807 " Media type: %s\n");
809 Jmsg(jcr, M_MOUNT, 0, msg,
810 dev->is_nospace()?_("\n\nWARNING: device is full! Please add more disk space then ...\n\n"):"",
816 Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
817 dcr->VolumeName, dev->print_name(), jcr->Job);
820 jcr->sendJobStatus(JS_WaitMount);
822 stat = wait_for_sysop(dcr); /* wait on device */
823 Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
825 Dmsg1(100, "Poll timeout in mount vol on device %s\n", dev->print_name());
826 Dmsg1(100, "Blocked=%s\n", dev->print_blocked());
830 if (stat == W_TIMEOUT) {
831 if (!double_dev_wait_time(dev)) {
832 Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
833 dev->print_name(), jcr->Job);
834 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
835 Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
837 return false; /* exceeded maximum waits */
841 if (stat == W_ERROR) {
843 Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
844 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
848 Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
853 jcr->sendJobStatus(JS_Running);
854 Dmsg0(100, "leave dir_ask_sysop_to_mount_volume\n");