]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Backport from BEE
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    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    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *  Subroutines to handle Catalog reqests sent to the Director
18  *   Reqests/commands from the Director are handled in dircmd.c
19  *
20  *   Kern Sibbald, December 2000
21  *
22  */
23
24 #include "bacula.h"                   /* pull in global headers */
25 #include "stored.h"                   /* pull in Storage Deamon headers */
26
27 static const int dbglvl = 200;
28
29 /* Requests sent to the Director */
30 static char Find_media[]   = "CatReq Job=%s FindMedia=%d pool_name=%s media_type=%s\n";
31 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
32 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
33    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
34    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
35    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
36    " VolFirstWritten=%s VolParts=%u\n";
37 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
38    " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
39    " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%s\n";
40 static char FileAttributes[] = "UpdCat Job=%s FileAttributes ";
41
42 /* Responses received from the Director */
43 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
44    " VolBlocks=%lu VolBytes=%lld VolMounts=%lu"
45    " VolErrors=%lu VolWrites=%lu"
46    " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s"
47    " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
48    " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
49    " VolParts=%lu LabelType=%ld MediaId=%lld ScratchPoolId=%lld\n";
50
51
52 static char OK_create[] = "1000 OK CreateJobMedia\n";
53
54 static bthread_mutex_t vol_info_mutex = BTHREAD_MUTEX_PRIORITY(PRIO_SD_VOL_INFO);
55
56 #ifdef needed
57
58 static char Device_update[] = "DevUpd Job=%s device=%s "
59    "append=%d read=%d num_writers=%d "
60    "open=%d labeled=%d offline=%d "
61    "reserved=%d max_writers=%d "
62    "autoselect=%d autochanger=%d "
63    "changer_name=%s media_type=%s volume_name=%s\n";
64
65
66 /** Send update information about a device to Director */
67 bool dir_update_device(JCR *jcr, DEVICE *dev)
68 {
69    BSOCK *dir = jcr->dir_bsock;
70    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
71    DEVRES *device = dev->device;
72    bool ok;
73
74    pm_strcpy(dev_name, device->hdr.name);
75    bash_spaces(dev_name);
76    if (dev->is_labeled()) {
77       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
78    } else {
79       pm_strcpy(VolumeName, "*");
80    }
81    bash_spaces(VolumeName);
82    pm_strcpy(MediaType, device->media_type);
83    bash_spaces(MediaType);
84    if (device->changer_res) {
85       pm_strcpy(ChangerName, device->changer_res->hdr.name);
86       bash_spaces(ChangerName);
87    } else {
88       pm_strcpy(ChangerName, "*");
89    }
90    ok = dir->fsend(Device_update,
91       jcr->Job,
92       dev_name.c_str(),
93       dev->can_append()!=0,
94       dev->can_read()!=0, dev->num_writers,
95       dev->is_open()!=0, dev->is_labeled()!=0,
96       dev->is_offline()!=0, dev->reserved_device,
97       dev->is_tape()?100000:1,
98       dev->autoselect, 0,
99       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
100    Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
101    return ok;
102 }
103
104 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
105 {
106    BSOCK *dir = jcr->dir_bsock;
107    POOL_MEM dev_name, MediaType;
108    DEVRES *device;
109    bool ok;
110
111    pm_strcpy(dev_name, changer->hdr.name);
112    bash_spaces(dev_name);
113    device = (DEVRES *)changer->device->first();
114    pm_strcpy(MediaType, device->media_type);
115    bash_spaces(MediaType);
116    /* This is mostly to indicate that we are here */
117    ok = dir->fsend(Device_update,
118       jcr->Job,
119       dev_name.c_str(),         /* Changer name */
120       0, 0, 0,                  /* append, read, num_writers */
121       0, 0, 0,                  /* is_open, is_labeled, offline */
122       0, 0,                     /* reserved, max_writers */
123       0,                        /* Autoselect */
124       changer->device->size(),  /* Number of devices */
125       "0",                      /* PoolId */
126       "*",                      /* ChangerName */
127       MediaType.c_str(),        /* MediaType */
128       "*");                     /* VolName */
129    Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
130    return ok;
131 }
132 #endif
133
134
135 /**
136  * Send current JobStatus to Director
137  */
138 bool dir_send_job_status(JCR *jcr)
139 {
140    return jcr->sendJobStatus();
141 }
142
143 /**
144  * Common routine for:
145  *   dir_get_volume_info()
146  * and
147  *   dir_find_next_appendable_volume()
148  *
149  *  NOTE!!! All calls to this routine must be protected by
150  *          locking vol_info_mutex before calling it so that
151  *          we don't have one thread modifying the parameters
152  *          and another reading them.
153  *
154  *  Returns: true  on success and vol info in dcr->VolCatInfo
155  *           false on failure
156  */
157 static bool do_get_volume_info(DCR *dcr)
158 {
159     JCR *jcr = dcr->jcr;
160     BSOCK *dir = jcr->dir_bsock;
161     VOLUME_CAT_INFO vol;
162     int n;
163     int32_t InChanger;
164
165     dcr->setVolCatInfo(false);
166     if (dir->recv() <= 0) {
167        Dmsg0(dbglvl, "getvolname error bnet_recv\n");
168        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
169        return false;
170     }
171     memset(&vol, 0, sizeof(vol));
172     Dmsg1(dbglvl, "<dird %s", dir->msg);
173     n = sscanf(dir->msg, OK_media, vol.VolCatName,
174                &vol.VolCatJobs, &vol.VolCatFiles,
175                &vol.VolCatBlocks, &vol.VolCatAmetaBytes,
176                &vol.VolCatMounts, &vol.VolCatErrors,
177                &vol.VolCatWrites, &vol.VolCatMaxBytes,
178                &vol.VolCatCapacityBytes, vol.VolCatStatus,
179                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
180                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
181                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
182                &vol.LabelType, &vol.VolMediaId, &vol.VolScratchPoolId);
183     if (n != 23) {
184        Dmsg1(dbglvl, "get_volume_info failed: ERR=%s", dir->msg);
185        /*
186         * Note, we can get an error here either because there is
187         *  a comm problem, or if the volume is not a suitable
188         *  volume to use, so do not issue a Jmsg() here, do it
189         *  in the calling routine.
190         */
191        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
192        return false;
193     }
194     vol.InChanger = InChanger;        /* bool in structure */
195     vol.is_valid = true;
196     vol.VolCatBytes = vol.VolCatAmetaBytes;
197     unbash_spaces(vol.VolCatName);
198     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
199     dcr->VolCatInfo = vol;            /* structure assignment */
200
201     Dmsg2(dbglvl, "do_reqest_vol_info return true slot=%d Volume=%s\n",
202           vol.Slot, vol.VolCatName);
203     Dmsg3(dbglvl, "Dir returned VolCatAmetaBytes=%lld Status=%s Vol=%s\n",
204        vol.VolCatAmetaBytes, vol.VolCatStatus, vol.VolCatName);
205     return true;
206 }
207
208
209 /**
210  * Get Volume info for a specific volume from the Director's Database
211  *
212  * Returns: true  on success   (Director guarantees that Pool and MediaType
213  *                              are correct and VolStatus==Append or
214  *                              VolStatus==Recycle)
215  *          false on failure
216  *
217  *          Volume information returned in dcr->VolCatInfo
218  */
219 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
220 {
221    JCR *jcr = dcr->jcr;
222    BSOCK *dir = jcr->dir_bsock;
223
224    P(vol_info_mutex);
225    dcr->setVolCatName(dcr->VolumeName);
226    bash_spaces(dcr->getVolCatName());
227    dir->fsend(Get_Vol_Info, jcr->Job, dcr->getVolCatName(),
228       writing==GET_VOL_INFO_FOR_WRITE?1:0);
229    Dmsg1(dbglvl, ">dird %s", dir->msg);
230    unbash_spaces(dcr->getVolCatName());
231    bool ok = do_get_volume_info(dcr);
232    V(vol_info_mutex);
233    return ok;
234 }
235
236
237
238 /**
239  * Get info on the next appendable volume in the Director's database
240  *
241  * Returns: true  on success dcr->VolumeName is volume
242  *                reserve_volume() called on Volume name
243  *          false on failure dcr->VolumeName[0] == 0
244  *                also sets dcr->found_in_use if at least one
245  *                in use volume was found.
246  *
247  *          Volume information returned in dcr
248  *
249  */
250 bool dir_find_next_appendable_volume(DCR *dcr)
251 {
252     JCR *jcr = dcr->jcr;
253     BSOCK *dir = jcr->dir_bsock;
254     bool rtn;
255     char lastVolume[MAX_NAME_LENGTH];
256
257     Dmsg2(dbglvl, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n",
258        dcr->is_reserved(), dcr->VolumeName);
259     Mmsg(jcr->errmsg, "Unknown error\n");
260
261     /*
262      * Try the thirty oldest or most available volumes.  Note,
263      *   the most available could already be mounted on another
264      *   drive, so we continue looking for a not in use Volume.
265      */
266     lock_volumes();
267     P(vol_info_mutex);
268     dcr->clear_found_in_use();
269     lastVolume[0] = 0;
270     for (int vol_index=1;  vol_index < 30; vol_index++) {
271        bash_spaces(dcr->media_type);
272        bash_spaces(dcr->pool_name);
273        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
274        unbash_spaces(dcr->media_type);
275        unbash_spaces(dcr->pool_name);
276        Dmsg1(dbglvl, ">dird %s", dir->msg);
277        if (do_get_volume_info(dcr)) {
278           /* Give up if we get the same volume name twice */
279           if (lastVolume[0] && strcmp(lastVolume, dcr->VolumeName) == 0) {
280              Mmsg(jcr->errmsg, "Director returned same volume name=%s twice.\n",
281                 lastVolume);
282              Dmsg1(dbglvl, "Got same vol = %s\n", lastVolume);
283              break;
284           }
285           bstrncpy(lastVolume, dcr->VolumeName, sizeof(lastVolume));
286           if (dcr->can_i_write_volume()) {
287              Dmsg1(dbglvl, "Call reserve_volume for write. Vol=%s\n", dcr->VolumeName);
288              if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
289                 Dmsg1(dbglvl, "%s", jcr->errmsg);
290                 if (dcr->dev->must_wait()) {
291                    rtn = false;
292                    dcr->VolumeName[0] = 0;
293                    goto get_out;
294                 }
295                 continue;
296              }
297              Dmsg1(dbglvl, "dir_find_next_appendable_volume return true. vol=%s\n",
298                 dcr->VolumeName);
299              rtn = true;
300              goto get_out;
301           } else {
302              Mmsg(jcr->errmsg, "Volume %s is in use.\n", dcr->VolumeName);
303              Dmsg1(dbglvl, "Volume %s is in use.\n", dcr->VolumeName);
304              /* If volume is not usable, it is in use by someone else */
305              dcr->set_found_in_use();
306              continue;
307           }
308        }
309        Dmsg2(dbglvl, "No vol. index %d return false. dev=%s\n", vol_index,
310           dcr->dev->print_name());
311        break;
312     }
313     rtn = false;
314     dcr->VolumeName[0] = 0;
315
316 get_out:
317     V(vol_info_mutex);
318     unlock_volumes();
319     if (!rtn && dcr->VolCatInfo.VolScratchPoolId != 0) {
320        Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
321        Dmsg2(000, "!!!!!!!!! Volume=%s rejected ScratchPoolId=%lld\n", dcr->VolumeName,
322           dcr->VolCatInfo.VolScratchPoolId);
323        Dmsg1(000, "%s", jcr->errmsg);
324     //} else {
325     //   Dmsg3(000, "Rtn=%d Volume=%s ScratchPoolId=%lld\n", rtn, dcr->VolumeName,
326     //      dcr->VolCatInfo.VolScratchPoolId);
327     }
328     return rtn;
329 }
330
331
332 /*
333  * After writing a Volume, send the updated statistics
334  * back to the director. The information comes from the
335  * dev record.
336  */
337 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
338 {
339    JCR *jcr = dcr->jcr;
340    BSOCK *dir = jcr->dir_bsock;
341    DEVICE *dev = dcr->dev;
342    VOLUME_CAT_INFO *vol;
343    char ed1[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
344    int InChanger;
345    bool ok = false;
346    POOL_MEM VolumeName;
347
348    /* If system job, do not update catalog */
349    if (jcr->getJobType() == JT_SYSTEM) {
350       return true;
351    }
352
353    vol = &dev->VolCatInfo;
354    if (vol->VolCatName[0] == 0) {
355       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
356       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
357       return false;
358    }
359
360    /* Lock during Volume update */
361    P(vol_info_mutex);
362    dev->Lock_VolCatInfo();
363    /* Just labeled or relabeled the tape */
364    if (label) {
365       dev->setVolCatStatus("Append");
366    }
367 // if (update_LastWritten) {
368       vol->VolLastWritten = time(NULL);
369 // }
370    pm_strcpy(VolumeName, vol->VolCatName);
371    bash_spaces(VolumeName);
372    InChanger = vol->InChanger;
373    dir->fsend(Update_media, jcr->Job,
374       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
375       vol->VolCatBlocks, edit_uint64(vol->VolCatAmetaBytes, ed1),
376       vol->VolCatMounts, vol->VolCatErrors,
377       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed4),
378       edit_uint64(vol->VolLastWritten, ed5),
379       vol->VolCatStatus, vol->Slot, label,
380       InChanger,                      /* bool in structure */
381       edit_int64(vol->VolReadTime, ed6),
382       edit_int64(vol->VolWriteTime, ed7),
383       edit_uint64(vol->VolFirstWritten, ed8),
384       vol->VolCatParts);
385     Dmsg1(100, ">dird %s", dir->msg);
386
387    /* Do not lock device here because it may be locked from label */
388    if (!jcr->is_canceled()) {
389       /*
390        * We sent info directly from dev to the Director.
391        *  What the Director sends back is first read into
392        *  the dcr with do_get_volume_info()
393        */
394       if (!do_get_volume_info(dcr)) {
395          Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
396          Dmsg2(dbglvl, _("Didn't get vol info vol=%s: ERR=%s"),
397             vol->VolCatName, jcr->errmsg);
398          goto bail_out;
399       }
400       Dmsg1(100, "get_volume_info() %s", dir->msg);
401       /* Update dev Volume info in case something changed (e.g. expired) */
402       dcr->VolCatInfo.VolCatAmetaBytes = dev->VolCatInfo.VolCatAmetaBytes;
403       dcr->VolCatInfo.VolCatFiles = dev->VolCatInfo.VolCatFiles;
404       bstrncpy(vol->VolCatStatus, dcr->VolCatInfo.VolCatStatus, sizeof(vol->VolCatStatus));
405       /* ***FIXME***  copy other fields that can change, if any */
406       ok = true;
407    }
408
409 bail_out:
410    dev->Unlock_VolCatInfo();
411    V(vol_info_mutex);
412    return ok;
413 }
414
415 /**
416  * After writing a Volume, create the JobMedia record.
417  */
418 bool dir_create_jobmedia_record(DCR *dcr, bool zero)
419 {
420    JCR *jcr = dcr->jcr;
421    BSOCK *dir = jcr->dir_bsock;
422    char ed1[50];
423
424    if (!dcr->WroteVol) {
425       return true;                    /* nothing written to the Volume */
426    }
427
428    /* If system job, do not update catalog */
429    if (jcr->getJobType() == JT_SYSTEM) {
430       return true;
431    }
432
433    /* Throw out records where FI is zero -- i.e. nothing done */
434    if (!zero && dcr->VolFirstIndex == 0 &&
435         (dcr->StartBlock != 0 || dcr->EndBlock != 0)) {
436       Dmsg7(dbglvl, "Discard: JobMedia Vol=%s wrote=%d MediaId=%d FI=%d LI=%d StartBlock=%d EndBlock=%d Suppressed\n",
437          dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
438          dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartBlock, dcr->EndBlock);
439       return true;
440    }
441
442    Dmsg7(100, "JobMedia Vol=%s wrote=%d MediaId=%d FI=%d LI=%d StartBlock=%d EndBlock=%d Wrote\n",
443       dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
444       dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartBlock, dcr->EndBlock);
445    dcr->WroteVol = false;
446    if (zero) {
447       /* Send dummy place holder to avoid purging */
448       dir->fsend(Create_job_media, jcr->Job,
449          0 , 0, 0, 0, 0, 0, 0, 0, edit_uint64(dcr->VolMediaId, ed1));
450    } else {
451       dir->fsend(Create_job_media, jcr->Job,
452          dcr->VolFirstIndex, dcr->VolLastIndex,
453          dcr->StartFile, dcr->EndFile,
454          dcr->StartBlock, dcr->EndBlock,
455          dcr->Copy, dcr->Stripe,
456          edit_uint64(dcr->VolMediaId, ed1));
457    }
458    Dmsg1(dbglvl, ">dird %s", dir->msg);
459    if (dir->recv() <= 0) {
460       Dmsg0(dbglvl, "create_jobmedia error bnet_recv\n");
461       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
462            dir->bstrerror());
463       return false;
464    }
465    Dmsg1(210, "<dird %s", dir->msg);
466    if (strcmp(dir->msg, OK_create) != 0) {
467       Dmsg1(dbglvl, "Bad response from Dir: %s\n", dir->msg);
468       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
469       return false;
470    }
471    return true;
472 }
473
474
475 /**
476  * Update File Attribute data
477  * We do the following:
478  *  1. expand the bsock buffer to be large enough
479  *  2. Write a "header" into the buffer with serialized data
480  *    VolSessionId
481  *    VolSeesionTime
482  *    FileIndex
483  *    Stream
484  *    data length that follows
485  *    start of raw byte data from the Device record.
486  * Note, this is primarily for Attribute data, but can
487  *   also handle any device record. The Director must know
488  *   the raw byte data format that is defined for each Stream.
489  * Now Restore Objects pass through here STREAM_RESTORE_OBJECT
490  */
491 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
492 {
493    JCR *jcr = dcr->jcr;
494    BSOCK *dir = jcr->dir_bsock;
495    ser_declare;
496
497 #ifdef NO_ATTRIBUTES_TEST
498    return true;
499 #endif
500
501    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
502                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
503    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
504                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
505    ser_begin(dir->msg + dir->msglen, 0);
506    ser_uint32(rec->VolSessionId);
507    ser_uint32(rec->VolSessionTime);
508    ser_int32(rec->FileIndex);
509    ser_int32(rec->Stream);
510    ser_uint32(rec->data_len);
511    ser_bytes(rec->data, rec->data_len);
512    dir->msglen = ser_length(dir->msg);
513    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
514    if (rec->maskedStream == STREAM_UNIX_ATTRIBUTES ||
515        rec->maskedStream == STREAM_UNIX_ATTRIBUTES_EX) {
516       Dmsg2(1500, "==== set_data_end FI=%ld %s\n", rec->FileIndex, rec->data);
517       dir->set_data_end(rec->FileIndex);    /* set offset of valid data */
518    }
519    return dir->send();
520 }
521
522
523 /**
524  *   Request the sysop to create an appendable volume
525  *
526  *   Entered with device blocked.
527  *   Leaves with device blocked.
528  *
529  *   Returns: true  on success (operator issues a mount command)
530  *            false on failure
531  *              Note, must create dev->errmsg on error return.
532  *
533  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
534  *      information on suggested volume, but this may not be the
535  *      same as what is actually mounted.
536  *
537  *    When we return with success, the correct tape may or may not
538  *      actually be mounted. The calling routine must read it and
539  *      verify the label.
540  */
541 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
542 {
543    int stat = W_TIMEOUT;
544    DEVICE *dev = dcr->dev;
545    JCR *jcr = dcr->jcr;
546    bool got_vol = false;
547
548    if (job_canceled(jcr)) {
549       return false;
550    }
551    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
552    ASSERT(dev->blocked());
553    for ( ;; ) {
554       if (job_canceled(jcr)) {
555          Mmsg(dev->errmsg,
556               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
557               jcr->Job, dev->print_name());
558          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
559          return false;
560       }
561       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
562       if (got_vol) {
563          goto get_out;
564       } else {
565          dev->clear_wait();
566          if (stat == W_TIMEOUT || stat == W_MOUNT) {
567             Mmsg(dev->errmsg, _(
568 "Job %s is waiting. Cannot find any appendable volumes.\n"
569 "Please use the \"label\" command to create a new Volume for:\n"
570 "    Storage:      %s\n"
571 "    Pool:         %s\n"
572 "    Media type:   %s\n"),
573                jcr->Job,
574                dev->print_name(),
575                dcr->pool_name,
576                dcr->media_type);
577             Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
578             Dmsg1(dbglvl, "%s", dev->errmsg);
579          }
580       }
581
582       jcr->sendJobStatus(JS_WaitMedia);
583
584       stat = wait_for_sysop(dcr);
585       Dmsg1(dbglvl, "Back from wait_for_sysop stat=%d\n", stat);
586       if (dev->poll) {
587          Dmsg1(dbglvl, "Poll timeout in create append vol on device %s\n", dev->print_name());
588          continue;
589       }
590
591       if (stat == W_TIMEOUT) {
592          if (!double_dev_wait_time(dev)) {
593             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
594                dev->print_name(), jcr->Job);
595             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
596             Dmsg1(dbglvl, "Gave up waiting on device %s\n", dev->print_name());
597             return false;             /* exceeded maximum waits */
598          }
599          continue;
600       }
601       if (stat == W_ERROR) {
602          berrno be;
603          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
604          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
605          return false;
606       }
607       Dmsg1(dbglvl, "Someone woke me for device %s\n", dev->print_name());
608    }
609
610 get_out:
611    jcr->sendJobStatus(JS_Running);
612    Dmsg0(dbglvl, "leave dir_ask_sysop_to_create_appendable_volume\n");
613    return true;
614 }
615
616 /**
617  *   Request to mount specific Volume
618  *
619  *   Entered with device blocked and dcr->VolumeName is desired
620  *      volume.
621  *   Leaves with device blocked.
622  *
623  *   Returns: true  on success (operator issues a mount command)
624  *            false on failure
625  *                  Note, must create dev->errmsg on error return.
626  *
627  */
628 bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool write_access)
629 {
630    int stat = W_TIMEOUT;
631    DEVICE *dev = dcr->dev;
632    JCR *jcr = dcr->jcr;
633
634    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
635    if (!dcr->VolumeName[0]) {
636       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
637       return false;
638    }
639
640    for ( ;; ) {
641       if (job_canceled(jcr)) {
642          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
643               jcr->Job, dev->print_name());
644          return false;
645       }
646
647       if (dev->is_dvd()) {
648          dev->unmount(0);
649       }
650
651       /*
652        * If we are not polling, and the wait timeout or the
653        *   user explicitly did a mount, send him the message.
654        *   Otherwise skip it.
655        */
656       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
657          char *msg;
658          if (write_access) {
659             msg = _("%sPlease mount append Volume \"%s\" or label a new one for:\n"
660               "    Job:          %s\n"
661               "    Storage:      %s\n"
662               "    Pool:         %s\n"
663               "    Media type:   %s\n");
664          } else {
665             msg = _("%sPlease mount read Volume \"%s\" for:\n"
666               "    Job:          %s\n"
667               "    Storage:      %s\n"
668               "    Pool:         %s\n"
669               "    Media type:   %s\n");
670          }
671          Jmsg(jcr, M_MOUNT, 0, msg,
672               dev->is_nospace()?_("\n\nWARNING: device is full! Please add more disk space then ...\n\n"):"",
673               dcr->VolumeName,
674               jcr->Job,
675               dev->print_name(),
676               dcr->pool_name,
677               dcr->media_type);
678          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
679                dcr->VolumeName, dev->print_name(), jcr->Job);
680       }
681
682       jcr->sendJobStatus(JS_WaitMount);
683
684       stat = wait_for_sysop(dcr);          /* wait on device */
685       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
686       if (dev->poll) {
687          Dmsg1(100, "Poll timeout in mount vol on device %s\n", dev->print_name());
688          Dmsg1(100, "Blocked=%s\n", dev->print_blocked());
689          goto get_out;
690       }
691
692       if (stat == W_TIMEOUT) {
693          if (!double_dev_wait_time(dev)) {
694             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
695                dev->print_name(), jcr->Job);
696             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
697             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
698             return false;             /* exceeded maximum waits */
699          }
700          continue;
701       }
702       if (stat == W_ERROR) {
703          berrno be;
704          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
705          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
706          return false;
707       }
708       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
709       break;
710    }
711
712 get_out:
713    jcr->sendJobStatus(JS_Running);
714    Dmsg0(100, "leave dir_ask_sysop_to_mount_volume\n");
715    return true;
716 }