]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Fix bug #2271 where poll interval causes tape mount message to repeat
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
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.
8
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.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Subroutines to handle Catalog reqests sent to the Director
21  *   Reqests/commands from the Director are handled in dircmd.c
22  *
23  *   Kern Sibbald, December 2000
24  *
25  */
26
27 #include "bacula.h"                   /* pull in global headers */
28 #include "stored.h"                   /* pull in Storage Deamon headers */
29
30 static const int dbglvl = 200;
31
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 ";
43
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";
53
54
55 static char OK_create[] = "1000 OK CreateJobMedia\n";
56
57 static bthread_mutex_t vol_info_mutex = BTHREAD_MUTEX_PRIORITY(PRIO_SD_VOL_INFO);
58
59 #ifdef needed
60
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 "
66    "enabled=%d "
67    "changer_name=%s media_type=%s volume_name=%s\n";
68
69
70 /** Send update information about a device to Director */
71 bool dir_update_device(JCR *jcr, DEVICE *dev)
72 {
73    BSOCK *dir = jcr->dir_bsock;
74    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
75    DEVRES *device = dev->device;
76    bool ok;
77
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);
82    } else {
83       pm_strcpy(VolumeName, "*");
84    }
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);
91    } else {
92       pm_strcpy(ChangerName, "*");
93    }
94    ok = dir->fsend(Device_update,
95       jcr->Job,
96       dev_name.c_str(),
97       dev->can_append()!=0,
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,
102       dev->autoselect, 0,
103       dev->enabled,
104       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
105    Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
106    return ok;
107 }
108
109 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
110 {
111    BSOCK *dir = jcr->dir_bsock;
112    POOL_MEM dev_name, MediaType;
113    DEVRES *device;
114    bool ok;
115
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,
123       jcr->Job,
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 */
128       0,                        /* Autoselect */
129       0,                        /* Enabled */
130       changer->device->size(),  /* Number of devices */
131       "0",                      /* PoolId */
132       "*",                      /* ChangerName */
133       MediaType.c_str(),        /* MediaType */
134       "*");                     /* VolName */
135    Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
136    return ok;
137 }
138 #endif
139
140
141 /**
142  * Send current JobStatus to Director
143  */
144 bool dir_send_job_status(JCR *jcr)
145 {
146    return jcr->sendJobStatus();
147 }
148
149 /**
150  * Common routine for:
151  *   dir_get_volume_info()
152  * and
153  *   dir_find_next_appendable_volume()
154  *
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.
159  *
160  *  Returns: true  on success and vol info in dcr->VolCatInfo
161  *           false on failure
162  */
163 static bool do_get_volume_info(DCR *dcr)
164 {
165     JCR *jcr = dcr->jcr;
166     BSOCK *dir = jcr->dir_bsock;
167     VOLUME_CAT_INFO vol;
168     int n;
169     int32_t InChanger;
170
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"));
175        return false;
176     }
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);
190     if (n != 26) {
191        Dmsg1(dbglvl, "get_volume_info failed: ERR=%s", dir->msg);
192        /*
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.
197         */
198        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
199        return false;
200     }
201     vol.InChanger = InChanger;        /* bool in structure */
202     vol.is_valid = true;
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 */
207
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);
213     return true;
214 }
215
216
217 /**
218  * Get Volume info for a specific volume from the Director's Database
219  *
220  * Returns: true  on success   (Director guarantees that Pool and MediaType
221  *                              are correct and VolStatus==Append or
222  *                              VolStatus==Recycle)
223  *          false on failure
224  *
225  *          Volume information returned in dcr->VolCatInfo
226  */
227 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
228 {
229    JCR *jcr = dcr->jcr;
230    BSOCK *dir = jcr->dir_bsock;
231
232    P(vol_info_mutex);
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);
240    V(vol_info_mutex);
241    return ok;
242 }
243
244
245
246 /**
247  * Get info on the next appendable volume in the Director's database
248  *
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.
254  *
255  *          Volume information returned in dcr
256  *
257  */
258 bool dir_find_next_appendable_volume(DCR *dcr)
259 {
260     JCR *jcr = dcr->jcr;
261     BSOCK *dir = jcr->dir_bsock;
262     bool rtn;
263     char lastVolume[MAX_NAME_LENGTH];
264
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");
268
269     /*
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.
273      */
274     lock_volumes();
275     P(vol_info_mutex);
276     dcr->clear_found_in_use();
277     lastVolume[0] = 0;
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,
282                   dcr->dev->dev_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",
290                 lastVolume);
291              Dmsg1(dbglvl, "Got same vol = %s\n", lastVolume);
292              break;
293           }
294           /*
295            * If we have VolType and we are disk or ameta, the VolType must match
296            */
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);
301              continue;
302           }
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()) {
309                    rtn = false;
310                    dcr->VolumeName[0] = 0;
311                    goto get_out;
312                 }
313                 continue;
314              }
315              Dmsg1(dbglvl, "dir_find_next_appendable_volume return true. vol=%s\n",
316                 dcr->VolumeName);
317              rtn = true;
318              goto get_out;
319           } else {
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();
324              continue;
325           }
326        }
327        Dmsg2(dbglvl, "No vol. index %d return false. dev=%s\n", vol_index,
328           dcr->dev->print_name());
329        break;
330     }
331     rtn = false;
332     dcr->VolumeName[0] = 0;
333
334 get_out:
335     V(vol_info_mutex);
336     unlock_volumes();
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);
342     //} else {
343     //   Dmsg3(000, "Rtn=%d Volume=%s ScratchPoolId=%lld\n", rtn, dcr->VolumeName,
344     //      dcr->VolCatInfo.VolScratchPoolId);
345     }
346     return rtn;
347 }
348
349
350 /*
351  * After writing a Volume, send the updated statistics
352  * back to the director. The information comes from the
353  * dev record.
354  */
355 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
356 {
357    JCR *jcr = dcr->jcr;
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];
362    int InChanger;
363    bool ok = false;
364    POOL_MEM VolumeName;
365
366    /* If system job, do not update catalog */
367    if (jcr->getJobType() == JT_SYSTEM) {
368       return true;
369    }
370
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"));
375       return false;
376    }
377
378    /* Lock during Volume update */
379    P(vol_info_mutex);
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 */
384    if (label) {
385       dev->setVolCatStatus("Append");
386    }
387 // if (update_LastWritten) {
388       vol->VolLastWritten = time(NULL);
389 // }
390    pm_strcpy(VolumeName, vol->VolCatName);
391    bash_spaces(VolumeName);
392    InChanger = vol->InChanger;
393    vol->VolCatHoleBytes = 0;
394
395    /* Set device type where this Volume used */
396    if (vol->VolCatType == 0) {
397       vol->VolCatType = dev->dev_type;
398    }
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),
412       vol->VolCatType);
413     Dmsg1(100, ">dird %s", dir->msg);
414
415    /* Do not lock device here because it may be locked from label */
416    if (!jcr->is_canceled()) {
417       /*
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()
421        */
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);
426          goto bail_out;
427       }
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));
432
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;
448       ok = true;
449    }
450
451 bail_out:
452    dev->Unlock_VolCatInfo();
453    V(vol_info_mutex);
454    return ok;
455 }
456
457 struct JOBMEDIA_ITEM {
458    dlink link;
459    uint32_t VolFirstIndex;
460    uint32_t VolLastIndex;
461    uint32_t StartFile;
462    uint32_t EndFile;
463    uint32_t StartBlock;
464    uint32_t EndBlock;
465    int64_t  VolMediaId;
466 };
467
468 void create_jobmedia_queue(JCR *jcr)
469 {
470    JOBMEDIA_ITEM *item = NULL;
471    jcr->jobmedia_queue = New(dlist(item, &item->link));
472 }
473
474 bool flush_jobmedia_queue(JCR *jcr)
475 {
476    JOBMEDIA_ITEM *item;
477    BSOCK *dir = jcr->dir_bsock;
478    bool ok;
479
480    if (!jcr->jobmedia_queue || jcr->jobmedia_queue->size() == 0) {
481       //Dmsg0(000, "No jobmedia_queue\n");
482       return true;     /* should never happen */
483    }
484    Dmsg1(400, "=== Flush jobmedia queue = %d\n", jcr->jobmedia_queue->size());
485
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,
492          item->VolMediaId);
493       Dmsg2(400, "sd->dir: ok=%d Jobmedia=%s", ok, dir->msg);
494    }
495    dir->signal(BNET_EOD);
496    jcr->jobmedia_queue->destroy();
497
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"),
501            dir->bstrerror());
502       return false;
503    }
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);
508       return false;
509    }
510    return true;
511 }
512
513 /*
514  * After writing a Volume, create the JobMedia record.
515  */
516 bool dir_create_jobmedia_record(DCR *dcr, bool zero)
517 {
518    JCR *jcr = dcr->jcr;
519    BSOCK *dir = jcr->dir_bsock;
520    JOBMEDIA_ITEM *item;
521    bool ok = true;;
522
523    if (!zero && !dcr->WroteVol) {
524       return true;
525    }
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 */
531    }
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);
536       return true;
537    }
538
539    /* If system job, do not update catalog */
540    if (jcr->getJobType() == JT_SYSTEM) {
541       return true;
542    }
543
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);
550       return true;
551    }
552
553    /*
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.
557     *
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
561     *   really correct.
562     */
563    if (jcr->is_JobStatus(JS_Incomplete)) {
564       dcr->VolLastIndex = dir->get_lastFileIndex();
565       Dmsg1(100, "======= Set FI=%ld\n", dcr->VolLastIndex);
566    }
567
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));
573    if (zero) {
574       item->VolFirstIndex = item->VolLastIndex = 0;
575       item->StartFile = item->EndFile = 0;
576       item->StartBlock = item->EndBlock = 0;
577       item->VolMediaId = dcr->VolMediaId;
578    } else {
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;
586    }
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);
591    }
592
593    dcr->VolFirstIndex = dcr->VolLastIndex = 0;
594    dcr->StartFile = dcr->EndFile = 0;
595    dcr->StartBlock = dcr->EndBlock = 0;
596    return ok;
597 }
598
599
600 /**
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
605  *    VolSessionId
606  *    VolSeesionTime
607  *    FileIndex
608  *    Stream
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
615  */
616 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
617 {
618    JCR *jcr = dcr->jcr;
619    BSOCK *dir = jcr->dir_bsock;
620    ser_declare;
621
622 #ifdef NO_ATTRIBUTES_TEST
623    return true;
624 #endif
625
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 */
643    }
644    return dir->send();
645 }
646
647
648 /**
649  *   Request the sysop to create an appendable volume
650  *
651  *   Entered with device blocked.
652  *   Leaves with device blocked.
653  *
654  *   Returns: true  on success (operator issues a mount command)
655  *            false on failure
656  *              Note, must create dev->errmsg on error return.
657  *
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.
661  *
662  *    When we return with success, the correct tape may or may not
663  *      actually be mounted. The calling routine must read it and
664  *      verify the label.
665  */
666 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
667 {
668    int stat = W_TIMEOUT;
669    DEVICE *dev = dcr->dev;
670    JCR *jcr = dcr->jcr;
671    bool got_vol = false;
672
673    if (job_canceled(jcr)) {
674       dev->poll = false;
675       return false;
676    }
677    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
678    ASSERT(dev->blocked());
679    for ( ;; ) {
680       if (job_canceled(jcr)) {
681          Mmsg(dev->errmsg,
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);
685          dev->poll = false;
686          return false;
687       }
688       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
689       if (got_vol) {
690          goto get_out;
691       } else {
692          dev->clear_wait();
693          if (stat == W_TIMEOUT || stat == W_MOUNT) {
694             Mmsg(dev->errmsg, _(
695 "Job %s is waiting. Cannot find any appendable volumes.\n"
696 "Please use the \"label\" command to create a new Volume for:\n"
697 "    Storage:      %s\n"
698 "    Pool:         %s\n"
699 "    Media type:   %s\n"),
700                jcr->Job,
701                dev->print_name(),
702                dcr->pool_name,
703                dcr->media_type);
704             Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
705             Dmsg1(dbglvl, "%s", dev->errmsg);
706          }
707       }
708
709       jcr->sendJobStatus(JS_WaitMedia);
710
711       stat = wait_for_sysop(dcr);
712       Dmsg1(dbglvl, "Back from wait_for_sysop stat=%d\n", stat);
713       if (dev->poll) {
714          Dmsg1(dbglvl, "Poll timeout in create append vol on device %s\n", dev->print_name());
715          continue;
716       }
717
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());
724             dev->poll = false;
725             return false;             /* exceeded maximum waits */
726          }
727          continue;
728       }
729       if (stat == W_ERROR) {
730          berrno be;
731          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
732          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
733          dev->poll = false;
734          return false;
735       }
736       Dmsg1(dbglvl, "Someone woke me for device %s\n", dev->print_name());
737    }
738
739 get_out:
740    dev->poll = false;
741    jcr->sendJobStatus(JS_Running);
742    Dmsg0(dbglvl, "leave dir_ask_sysop_to_create_appendable_volume\n");
743    return true;
744 }
745
746 /**
747  *   Request to mount specific Volume
748  *
749  *   Entered with device blocked and dcr->VolumeName is desired
750  *      volume.
751  *   Leaves with device blocked.
752  *
753  *   Returns: true  on success (operator issues a mount command)
754  *            false on failure
755  *                  Note, must create dev->errmsg on error return.
756  *
757  */
758 bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool write_access)
759 {
760    int stat = W_TIMEOUT;
761    DEVICE *dev = dcr->dev;
762    JCR *jcr = dcr->jcr;
763
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"));
767       dev->poll = false;
768       return false;
769    }
770
771    if (dcr->no_mount_request) {
772       Mmsg(dev->errmsg, _("The current operation doesn't support mount request\n"));
773       dev->poll = false;
774       return false;
775    }
776
777    for ( ;; ) {
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());
781          dev->poll = false;
782          return false;
783       }
784
785       if (dev->is_dvd()) {
786          dev->unmount(0);
787       }
788
789       /*
790        * If we are not polling, and the wait timeout or the
791        *   user explicitly did a mount, send him the message.
792        *   Otherwise skip it.
793        */
794       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
795          const char *msg;
796          if (write_access) {
797             msg = _("%sPlease mount append Volume \"%s\" or label a new one for:\n"
798               "    Job:          %s\n"
799               "    Storage:      %s\n"
800               "    Pool:         %s\n"
801               "    Media type:   %s\n");
802          } else {
803             msg = _("%sPlease mount read Volume \"%s\" for:\n"
804               "    Job:          %s\n"
805               "    Storage:      %s\n"
806               "    Pool:         %s\n"
807               "    Media type:   %s\n");
808          }
809          Jmsg(jcr, M_MOUNT, 0, msg,
810               dev->is_nospace()?_("\n\nWARNING: device is full! Please add more disk space then ...\n\n"):"",
811               dcr->VolumeName,
812               jcr->Job,
813               dev->print_name(),
814               dcr->pool_name,
815               dcr->media_type);
816          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
817                dcr->VolumeName, dev->print_name(), jcr->Job);
818       }
819
820       jcr->sendJobStatus(JS_WaitMount);
821
822       stat = wait_for_sysop(dcr);          /* wait on device */
823       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
824       if (dev->poll) {
825          Dmsg1(100, "Poll timeout in mount vol on device %s\n", dev->print_name());
826          Dmsg1(100, "Blocked=%s\n", dev->print_blocked());
827          goto get_out;
828       }
829
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());
836             dev->poll = false;
837             return false;             /* exceeded maximum waits */
838          }
839          continue;
840       }
841       if (stat == W_ERROR) {
842          berrno be;
843          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
844          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
845          dev->poll = false;
846          return false;
847       }
848       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
849       break;
850    }
851
852 get_out:
853    jcr->sendJobStatus(JS_Running);
854    Dmsg0(100, "leave dir_ask_sysop_to_mount_volume\n");
855    return true;
856 }