2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2001-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
22 * Bacula Director -- catreq.c -- handles the message channel
23 * catalog request from the Storage daemon.
25 * Kern Sibbald, March MMI
27 * This routine runs as a thread and must be thread reentrant.
29 * Basic tasks done here:
30 * Handle Catalog services.
36 #include "findlib/find.h"
39 * Handle catalog request
40 * For now, we simply return next Volume to be used
43 /* Requests from the Storage daemon */
44 static char Find_media[] = "CatReq Job=%127s FindMedia=%d pool_name=%127s media_type=%127s vol_type=%d\n";
45 static char Get_Vol_Info[] = "CatReq Job=%127s GetVolInfo VolName=%127s write=%d\n";
47 static char Update_media[] = "CatReq Job=%127s UpdateMedia VolName=%s"
48 " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%lld VolABytes=%lld"
49 " VolHoleBytes=%lld VolHoles=%u VolMounts=%u"
50 " VolErrors=%u VolWrites=%lld MaxVolBytes=%lld EndTime=%lld VolStatus=%10s"
51 " Slot=%d relabel=%d InChanger=%d VolReadTime=%lld VolWriteTime=%lld"
52 " VolFirstWritten=%lld VolType=%u\n";
54 static char Create_jobmedia[] = "CatReq Job=%127s CreateJobMedia\n";
56 /* Responses sent to Storage daemon */
57 static char OK_media[] = "1000 OK VolName=%s VolJobs=%u VolFiles=%u"
58 " VolBlocks=%u VolBytes=%s VolABytes=%s VolHoleBytes=%s VolHoles=%u"
59 " VolMounts=%u VolErrors=%u VolWrites=%s"
60 " MaxVolBytes=%s VolCapacityBytes=%s VolStatus=%s Slot=%d"
61 " MaxVolJobs=%u MaxVolFiles=%u InChanger=%d VolReadTime=%s"
62 " VolWriteTime=%s EndFile=%u EndBlock=%u VolType=%u LabelType=%d"
63 " MediaId=%s ScratchPoolId=%s\n";
65 static char OK_create[] = "1000 OK CreateJobMedia\n";
68 static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr)
71 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50],
74 jcr->MediaId = mr->MediaId;
75 pm_strcpy(jcr->VolumeName, mr->VolumeName);
76 bash_spaces(mr->VolumeName);
77 stat = sd->fsend(OK_media, mr->VolumeName, mr->VolJobs,
78 mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
79 edit_uint64(mr->VolABytes, ed2),
80 edit_uint64(mr->VolHoleBytes, ed3),
81 mr->VolHoles, mr->VolMounts, mr->VolErrors,
82 edit_uint64(mr->VolWrites, ed4),
83 edit_uint64(mr->MaxVolBytes, ed5),
84 edit_uint64(mr->VolCapacityBytes, ed6),
85 mr->VolStatus, mr->Slot, mr->MaxVolJobs, mr->MaxVolFiles,
87 edit_int64(mr->VolReadTime, ed7),
88 edit_int64(mr->VolWriteTime, ed8),
89 mr->EndFile, mr->EndBlock,
92 edit_uint64(mr->MediaId, ed9),
93 edit_uint64(mr->ScratchPoolId, ed10));
94 unbash_spaces(mr->VolumeName);
95 Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg);
99 /* TODO: See if we want to let the FD do all kind
100 * of catalog request/update
102 void catalog_request(JCR *jcr, BSOCK *bs)
106 char Job[MAX_NAME_LENGTH];
107 char pool_name[MAX_NAME_LENGTH];
108 int index, ok, label, writing;
112 utime_t VolFirstWritten;
113 utime_t VolLastWritten;
116 memset(&sdmr, 0, sizeof(sdmr));
117 memset(&jm, 0, sizeof(jm));
121 * Request to find next appendable Volume for this Job
123 Dmsg1(200, "catreq %s", bs->msg);
125 omsg = get_memory(bs->msglen+1);
126 pm_strcpy(omsg, bs->msg);
127 bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
128 Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request; DB not open: %s"), omsg);
133 * Find next appendable medium for SD
135 n = sscanf(bs->msg, Find_media, &Job, &index, &pool_name, &mr.MediaType, &mr.VolType);
137 memset(&pr, 0, sizeof(pr));
138 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
139 unbash_spaces(pr.Name);
140 ok = db_get_pool_record(jcr, jcr->db, &pr);
142 mr.PoolId = pr.PoolId;
143 set_storageid_in_mr(jcr->wstore, &mr);
144 mr.ScratchPoolId = pr.ScratchPoolId;
145 ok = find_next_volume_for_append(jcr, &mr, index, fnv_create_vol, fnv_prune);
146 Dmsg3(050, "find_media ok=%d idx=%d vol=%s\n", ok, index, mr.VolumeName);
148 /* Report problem finding pool */
149 Jmsg1(jcr, M_WARNING, 0, _("Pool \"%s\" not found for SD find media request.\n"),
153 * Send Find Media response to Storage daemon
156 send_volume_info_to_storage_daemon(jcr, bs, &mr);
158 bs->fsend(_("1901 No Media.\n"));
159 Dmsg0(500, "1901 No Media.\n");
163 Dmsg1(1000, "Tried find_media. fields wanted=4, got=%d\n", n);
166 * Request to find specific Volume information
168 n = sscanf(bs->msg, Get_Vol_Info, &Job, &mr.VolumeName, &writing);
170 Dmsg1(100, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName);
174 unbash_spaces(mr.VolumeName);
175 if (db_get_media_record(jcr, jcr->db, &mr)) {
176 const char *reason = NULL; /* detailed reason for rejection */
178 * If we are reading, accept any volume (reason == NULL)
179 * If we are writing, check if the Volume is valid
180 * for this job, and do a recycle if necessary
184 * SD wants to write this Volume, so make
185 * sure it is suitable for this job, i.e.
186 * Pool matches, and it is either Append or Recycle
187 * and Media Type matches and Pool allows any volume.
189 if (mr.PoolId != jcr->jr.PoolId) {
190 reason = _("not in Pool");
191 } else if (strcmp(mr.MediaType, jcr->wstore->media_type) != 0) {
192 reason = _("not correct MediaType");
195 * Now try recycling if necessary
196 * reason set non-NULL if we cannot use it
198 check_if_volume_valid_or_recyclable(jcr, &mr, &reason);
201 if (!reason && mr.Enabled != 1) {
202 reason = _("is not Enabled");
204 if (reason == NULL) {
206 * Send Find Media response to Storage daemon
208 send_volume_info_to_storage_daemon(jcr, bs, &mr);
210 /* Not suitable volume */
211 bs->fsend(_("1998 Volume \"%s\" catalog status is %s, %s.\n"), mr.VolumeName,
212 mr.VolStatus, reason);
216 bs->fsend(_("1997 Volume \"%s\" not in catalog.\n"), mr.VolumeName);
217 Dmsg1(100, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
221 Dmsg1(1000, "Tried get_vol_info. fields wanted=3, got=%d\n", n);
225 * Request to update Media record. Comes typically at the end
226 * of a Storage daemon Job Session, when labeling/relabeling a
227 * Volume, or when an EOF mark is written.
229 n = sscanf(bs->msg, Update_media, &Job, &sdmr.VolumeName,
230 &sdmr.VolJobs, &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes,
231 &sdmr.VolABytes, &sdmr.VolHoleBytes, &sdmr.VolHoles,
232 &sdmr.VolMounts, &sdmr.VolErrors, &sdmr.VolWrites, &sdmr.MaxVolBytes,
233 &VolLastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger,
234 &sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten,
238 Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
239 mr.VolStatus, sdmr.VolStatus);
240 bstrncpy(mr.VolumeName, sdmr.VolumeName, sizeof(mr.VolumeName)); /* copy Volume name */
241 unbash_spaces(mr.VolumeName);
242 if (!db_get_media_record(jcr, jcr->db, &mr)) {
243 Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"),
244 mr.VolumeName, db_strerror(jcr->db));
245 bs->fsend(_("1991 Catalog Request for vol=%s failed: %s"),
246 mr.VolumeName, db_strerror(jcr->db));
250 /* Set first written time if this is first job */
251 if (mr.FirstWritten == 0) {
252 if (VolFirstWritten == 0) {
253 mr.FirstWritten = jcr->start_time; /* use Job start time as first write */
255 mr.FirstWritten = VolFirstWritten;
257 mr.set_first_written = true;
259 /* If we just labeled the tape set time */
260 if (label || mr.LabelDate == 0) {
261 mr.LabelDate = jcr->start_time;
262 mr.set_label_date = true;
263 if (mr.InitialWrite == 0) {
264 mr.InitialWrite = jcr->start_time;
266 Dmsg2(400, "label=%d labeldate=%d\n", label, mr.LabelDate);
269 * Insanity check for VolFiles get set to a smaller value
271 if (sdmr.VolFiles < mr.VolFiles) {
272 Jmsg(jcr, M_INFO, 0, _("Attempt to set Volume Files from %u to %u"
273 " for Volume \"%s\". Ignored.\n"),
274 mr.VolFiles, sdmr.VolFiles, mr.VolumeName);
275 sdmr.VolFiles = mr.VolFiles; /* keep orginal value */
278 Dmsg2(400, "Update media: BefVolJobs=%u After=%u\n", mr.VolJobs, sdmr.VolJobs);
281 * Check if the volume has been written by the job,
282 * and update the LastWritten field if needed.
284 if (mr.VolBlocks != sdmr.VolBlocks && VolLastWritten != 0) {
285 mr.LastWritten = VolLastWritten;
289 * Update to point to the last device used to write the Volume.
290 * However, do so only if we are writing the tape, i.e.
291 * the number of VolWrites has increased.
293 if (jcr->wstore && sdmr.VolWrites > mr.VolWrites) {
294 Dmsg2(050, "Update StorageId old=%d new=%d\n",
295 mr.StorageId, jcr->wstore->StorageId);
296 /* Update StorageId after write */
297 set_storageid_in_mr(jcr->wstore, &mr);
299 /* Nothing written, reset same StorageId */
300 set_storageid_in_mr(NULL, &mr);
303 /* Copy updated values to original media record */
304 mr.VolJobs = sdmr.VolJobs;
305 mr.VolFiles = sdmr.VolFiles;
306 mr.VolBlocks = sdmr.VolBlocks;
307 mr.VolBytes = sdmr.VolBytes;
308 mr.VolABytes = sdmr.VolABytes;
309 mr.VolHoleBytes = sdmr.VolHoleBytes;
310 mr.VolHoles = sdmr.VolHoles;
311 mr.VolMounts = sdmr.VolMounts;
312 mr.VolErrors = sdmr.VolErrors;
313 mr.VolWrites = sdmr.VolWrites;
315 mr.InChanger = sdmr.InChanger;
316 mr.VolType = sdmr.VolType;
317 bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
318 if (sdmr.VolReadTime >= 0) {
319 mr.VolReadTime = sdmr.VolReadTime;
321 if (sdmr.VolWriteTime >= 0) {
322 mr.VolWriteTime = sdmr.VolWriteTime;
325 Dmsg2(400, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
327 * Update the database, then before sending the response to the
328 * SD, check if the Volume has expired.
330 if (!db_update_media_record(jcr, jcr->db, &mr)) {
331 Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"),
332 db_strerror(jcr->db));
333 bs->fsend(_("1993 Update Media error\n"));
334 Pmsg0(000, "1993 Update Media error\n");
336 (void)has_volume_expired(jcr, &mr);
337 send_volume_info_to_storage_daemon(jcr, bs, &mr);
342 Dmsg1(1000, "Tried update_media. fields wanted=20, got=%d\n", n);
345 * Request to create a JobMedia record
347 if (sscanf(bs->msg, Create_jobmedia, &Job) == 1) {
349 jm.JobId = jcr->wjcr->JobId;
351 jm.JobId = jcr->JobId;
355 db_start_transaction(jcr, jcr->db);
356 while (bs->recv() >= 0) {
357 if (ok && sscanf(bs->msg, "%u %u %u %u %u %u %lld\n",
358 &jm.FirstIndex, &jm.LastIndex, &jm.StartFile, &jm.EndFile,
359 &jm.StartBlock, &jm.EndBlock, &MediaId) != 7) {
364 jm.MediaId = MediaId;
365 Dmsg6(400, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n",
366 jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex);
367 ok = db_create_jobmedia_record(jcr, jcr->db, &jm);
370 db_end_transaction(jcr, jcr->db);
372 Jmsg(jcr, M_FATAL, 0, _("Catalog error creating JobMedia record. %s"),
373 db_strerror(jcr->db));
375 bs->fsend(_("1992 Create JobMedia error\n"));
379 Dmsg0(400, "JobMedia record created\n");
380 bs->fsend(OK_create);
384 /* Handle snapshot catalog request */
385 if (snapshot_catreq(jcr, bs)) {
389 Dmsg1(1000, "Tried create_jobmedia. fields wanted=10, got=%d\n", n);
391 /* Everything failed. Send error message. */
392 omsg = get_memory(bs->msglen+1);
393 pm_strcpy(omsg, bs->msg);
394 bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
395 Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request: %s"), omsg);
399 Dmsg1(400, ">CatReq response: %s", bs->msg);
400 Dmsg1(400, "Leave catreq jcr 0x%x\n", jcr);
405 * Note, we receive the whole attribute record, but we select out only the stat
406 * packet, VolSessionId, VolSessionTime, FileIndex, file type, and file name to
407 * store in the catalog.
409 static void update_attribute(JCR *jcr, char *msg, int32_t msglen)
412 uint32_t VolSessionId, VolSessionTime;
421 /* Start transaction allocates jcr->attr and jcr->ar if needed */
422 db_start_transaction(jcr, jcr->db); /* start transaction if not already open */
426 * Start by scanning directly in the message buffer to get Stream
427 * there may be a cached attr so we cannot yet write into
428 * jcr->attr or jcr->ar
431 skip_nonspaces(&p); /* UpdCat */
433 skip_nonspaces(&p); /* Job=nnn */
435 skip_nonspaces(&p); /* "FileAttributes" */
437 /* The following "SD header" fields are serialized */
439 unser_uint32(VolSessionId); /* VolSessionId */
440 unser_uint32(VolSessionTime); /* VolSessionTime */
441 unser_int32(FileIndex); /* FileIndex */
442 unser_int32(Stream); /* Stream */
443 unser_uint32(reclen); /* Record length */
444 p += unser_length(p); /* Raw record follows */
447 * At this point p points to the raw record, which varies according
448 * to what kind of a record (Stream) was sent. Note, the integer
449 * fields at the beginning of these "raw" records are in ASCII with
450 * spaces between them so one can use scanf or manual scanning to
451 * extract the fields.
456 * Filename (full path)
458 * Link name (if type==FT_LNK or FT_LNKSAVED)
459 * Encoded extended-attributes (for Win32)
460 * Delta sequence number (32 bit int)
466 * Object_len (possibly compressed)
467 * Object_full_len (not compressed)
474 Dmsg1(400, "UpdCat msg=%s\n", msg);
475 Dmsg5(400, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d reclen=%d\n",
476 VolSessionId, VolSessionTime, FileIndex, Stream, reclen);
478 if (Stream == STREAM_UNIX_ATTRIBUTES || Stream == STREAM_UNIX_ATTRIBUTES_EX) {
479 if (jcr->cached_attribute) {
480 Dmsg2(400, "Cached attr. Stream=%d fname=%s\n", ar->Stream, ar->fname);
481 if (!db_create_attributes_record(jcr, jcr->db, ar)) {
482 Jmsg1(jcr, M_FATAL, 0, _("Attribute create error: ERR=%s"), db_strerror(jcr->db));
484 jcr->cached_attribute = false;
486 /* Any cached attr is flushed so we can reuse jcr->attr and jcr->ar */
487 jcr->attr = check_pool_memory_size(jcr->attr, msglen);
488 memcpy(jcr->attr, msg, msglen);
489 p = jcr->attr - msg + p; /* point p into jcr->attr */
490 skip_nonspaces(&p); /* skip FileIndex */
492 ar->FileType = str_to_int32(p);
493 skip_nonspaces(&p); /* skip FileType */
496 len = strlen(fname); /* length before attributes */
497 attr = &fname[len+1];
499 if (ar->FileType == FT_REG) {
500 p = attr + strlen(attr) + 1; /* point to link */
501 p = p + strlen(p) + 1; /* point to extended attributes */
502 p = p + strlen(p) + 1; /* point to delta sequence */
504 * Older FDs don't have a delta sequence, so check if it is there
506 if (p - jcr->attr < msglen) {
507 ar->DeltaSeq = str_to_int32(p); /* delta_seq */
511 Dmsg2(400, "dird<stored: stream=%d %s\n", Stream, fname);
512 Dmsg1(400, "dird<stored: attr=%s\n", attr);
515 if (ar->FileType == FT_DELETED) {
516 ar->FileIndex = 0; /* special value */
518 ar->FileIndex = FileIndex;
523 ar->JobId = jcr->wjcr->JobId;
524 Dmsg1(100, "=== set JobId=%d\n", ar->JobId);
526 ar->JobId = jcr->JobId;
529 ar->DigestType = CRYPTO_DIGEST_NONE;
530 jcr->cached_attribute = true;
532 Dmsg2(400, "dird<filed: stream=%d %s\n", Stream, fname);
533 Dmsg1(400, "dird<filed: attr=%s\n", attr);
535 } else if (Stream == STREAM_RESTORE_OBJECT) {
538 memset(&ro, 0, sizeof(ro));
540 ro.FileIndex = FileIndex;
542 ro.JobId = jcr->wjcr->JobId;
543 Dmsg1(100, "=== set JobId=%d\n", ar->JobId);
545 ro.JobId = jcr->JobId;
548 Dmsg1(100, "Robj=%s\n", p);
550 skip_nonspaces(&p); /* skip FileIndex */
552 ro.FileType = str_to_int32(p); /* FileType */
555 ro.object_index = str_to_int32(p); /* Object Index */
558 ro.object_len = str_to_int32(p); /* object length possibly compressed */
561 ro.object_full_len = str_to_int32(p); /* uncompressed object length */
564 ro.object_compression = str_to_int32(p); /* compression */
568 ro.plugin_name = p; /* point to plugin name */
569 len = strlen(ro.plugin_name);
570 ro.object_name = &ro.plugin_name[len+1]; /* point to object name */
571 len = strlen(ro.object_name);
572 ro.object = &ro.object_name[len+1]; /* point to object */
573 ro.object[ro.object_len] = 0; /* add zero for those who attempt printing */
574 Dmsg7(100, "oname=%s stream=%d FT=%d FI=%d JobId=%d, obj_len=%d\nobj=\"%s\"\n",
575 ro.object_name, ro.Stream, ro.FileType, ro.FileIndex, ro.JobId,
576 ro.object_len, ro.object);
578 if (!db_create_restore_object_record(jcr, jcr->db, &ro)) {
579 Jmsg1(jcr, M_FATAL, 0, _("Restore object create error. %s"), db_strerror(jcr->db));
580 jcr->cached_attribute = false;
583 } else if (crypto_digest_stream_type(Stream) != CRYPTO_DIGEST_NONE) {
585 if (ar->FileIndex != FileIndex) {
586 Jmsg3(jcr, M_WARNING, 0, _("%s not same File=%d as attributes=%d\n"),
587 stream_to_ascii(Stream), FileIndex, ar->FileIndex);
589 /* Update digest in catalog */
590 char digestbuf[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
592 int type = CRYPTO_DIGEST_NONE;
595 case STREAM_MD5_DIGEST:
596 len = CRYPTO_DIGEST_MD5_SIZE;
597 type = CRYPTO_DIGEST_MD5;
599 case STREAM_SHA1_DIGEST:
600 len = CRYPTO_DIGEST_SHA1_SIZE;
601 type = CRYPTO_DIGEST_SHA1;
603 case STREAM_SHA256_DIGEST:
604 len = CRYPTO_DIGEST_SHA256_SIZE;
605 type = CRYPTO_DIGEST_SHA256;
607 case STREAM_SHA512_DIGEST:
608 len = CRYPTO_DIGEST_SHA512_SIZE;
609 type = CRYPTO_DIGEST_SHA512;
612 /* Never reached ... */
613 Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. Unsupported digest stream type: %d"),
617 bin_to_base64(digestbuf, sizeof(digestbuf), fname, len, true);
618 Dmsg3(400, "DigestLen=%d Digest=%s type=%d\n", strlen(digestbuf),
620 if (jcr->cached_attribute) {
621 ar->Digest = digestbuf;
622 ar->DigestType = type;
623 Dmsg2(400, "Cached attr with digest. Stream=%d fname=%s\n",
624 ar->Stream, ar->fname);
626 /* Update BaseFile table */
627 if (!db_create_attributes_record(jcr, jcr->db, ar)) {
628 Jmsg1(jcr, M_FATAL, 0, _("attribute create error. ERR=%s"),
629 db_strerror(jcr->db));
631 jcr->cached_attribute = false;
633 if (!db_add_digest_to_file_record(jcr, jcr->db, ar->FileId, digestbuf, type)) {
634 Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. %s"),
635 db_strerror(jcr->db));
643 * Update File Attributes in the catalog with data
644 * sent by the Storage daemon.
646 void catalog_update(JCR *jcr, BSOCK *bs)
648 if (!jcr->pool->catalog_files) {
649 return; /* user disabled cataloging */
651 if (jcr->is_job_canceled()) {
655 POOLMEM *omsg = get_memory(bs->msglen+1);
656 pm_strcpy(omsg, bs->msg);
657 bs->fsend(_("1994 Invalid Catalog Update: %s"), omsg);
658 Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog Update; DB not open: %s"), omsg);
662 update_attribute(jcr, bs->msg, bs->msglen);
665 if (jcr->is_job_canceled()) {
666 jcr->cached_attribute = false;
667 cancel_storage_daemon_job(jcr);
672 * Update File Attributes in the catalog with data read from
673 * the storage daemon spool file. We receive the filename and
676 bool despool_attributes_from_file(JCR *jcr, const char *file)
682 int32_t msglen; /* message length */
683 POOLMEM *msg = get_pool_memory(PM_MESSAGE);
686 Dmsg1(100, "Begin despool_attributes_from_file\n", file);
688 if (jcr->is_job_canceled() || !jcr->pool->catalog_files || !jcr->db) {
689 goto bail_out; /* user disabled cataloging */
692 spool_fd = fopen(file, "rb");
694 Dmsg0(100, "cancel despool_attributes_from_file\n");
695 /* send an error message */
698 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
699 posix_fadvise(fileno(spool_fd), 0, 0, POSIX_FADV_WILLNEED);
702 while (fread((char *)&pktsiz, 1, sizeof(int32_t), spool_fd) ==
704 size += sizeof(int32_t);
705 msglen = ntohl(pktsiz);
707 if (msglen > (int32_t) sizeof_pool_memory(msg)) {
708 msg = realloc_pool_memory(msg, msglen + 1);
710 nbytes = fread(msg, 1, msglen, spool_fd);
711 if (nbytes != (size_t) msglen) {
713 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, msglen);
714 Qmsg1(jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
720 if (!jcr->is_job_canceled()) {
721 update_attribute(jcr, msg, msglen);
722 if (jcr->is_job_canceled() || (jcr->wjcr && jcr->wjcr->is_job_canceled())) {
727 if (ferror(spool_fd)) {
729 Qmsg1(jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
731 Dmsg1(050, "fread attr spool error. ERR=%s\n", be.bstrerror());
741 if (jcr->is_job_canceled()) {
742 jcr->cached_attribute = false;
743 cancel_storage_daemon_job(jcr);
746 free_pool_memory(msg);
747 Dmsg1(100, "End despool_attributes_from_file ret=%i\n", ret);