]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
f6fd066898c59fcd93fd5c8695d61ae7e53f8be2
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Subroutines to handle Catalog reqests sent to the Director
30  *   Reqests/commands from the Director are handled in dircmd.c
31  *
32  *   Kern Sibbald, December 2000
33  *
34  *   Version $Id$
35  */
36
37 #include "bacula.h"                   /* pull in global headers */
38 #include "stored.h"                   /* pull in Storage Deamon headers */
39
40 /* Requests sent to the Director */
41 static char Find_media[]   = "CatReq Job=%s FindMedia=%d pool_name=%s media_type=%s\n";
42 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
43 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
44    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
45    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
46    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
47    " VolFirstWritten=%s VolParts=%u\n";
48 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
49    " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
50    " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%s\n";
51 static char FileAttributes[] = "UpdCat Job=%s FileAttributes ";
52 static char Job_status[]     = "Status Job=%s JobStatus=%d\n";
53
54 /* Responses received from the Director */
55 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
56    " VolBlocks=%lu VolBytes=%lld VolMounts=%lu VolErrors=%lu VolWrites=%lu"
57    " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s"
58    " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
59    " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
60    " VolParts=%lu LabelType=%ld MediaId=%lld\n";
61
62
63 static char OK_create[] = "1000 OK CreateJobMedia\n";
64
65 static pthread_mutex_t vol_info_mutex = PTHREAD_MUTEX_INITIALIZER;
66
67 #ifdef needed
68
69 static char Device_update[] = "DevUpd Job=%s device=%s "
70    "append=%d read=%d num_writers=%d "
71    "open=%d labeled=%d offline=%d "
72    "reserved=%d max_writers=%d "
73    "autoselect=%d autochanger=%d "
74    "changer_name=%s media_type=%s volume_name=%s\n";
75
76
77 /* Send update information about a device to Director */
78 bool dir_update_device(JCR *jcr, DEVICE *dev)
79 {
80    BSOCK *dir = jcr->dir_bsock;
81    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
82    DEVRES *device = dev->device;
83    bool ok;
84    
85    pm_strcpy(dev_name, device->hdr.name);
86    bash_spaces(dev_name);
87    if (dev->is_labeled()) {
88       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
89    } else {
90       pm_strcpy(VolumeName, "*");
91    }
92    bash_spaces(VolumeName);
93    pm_strcpy(MediaType, device->media_type);
94    bash_spaces(MediaType);
95    if (device->changer_res) {
96       pm_strcpy(ChangerName, device->changer_res->hdr.name);
97       bash_spaces(ChangerName);
98    } else {
99       pm_strcpy(ChangerName, "*");
100    }
101    ok =bnet_fsend(dir, Device_update, 
102       jcr->Job,
103       dev_name.c_str(),
104       dev->can_append()!=0,
105       dev->can_read()!=0, dev->num_writers, 
106       dev->is_open()!=0, dev->is_labeled()!=0,
107       dev->is_offline()!=0, dev->reserved_device, 
108       dev->is_tape()?100000:1,
109       dev->autoselect, 0, 
110       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
111    Dmsg1(100, ">dird: %s\n", dir->msg);
112    return ok;
113 }
114
115 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
116 {
117    BSOCK *dir = jcr->dir_bsock;
118    POOL_MEM dev_name, MediaType;
119    DEVRES *device;
120    bool ok;
121
122    pm_strcpy(dev_name, changer->hdr.name);
123    bash_spaces(dev_name);
124    device = (DEVRES *)changer->device->first();
125    pm_strcpy(MediaType, device->media_type);
126    bash_spaces(MediaType);
127    /* This is mostly to indicate that we are here */
128    ok = bnet_fsend(dir, Device_update,
129       jcr->Job,
130       dev_name.c_str(),         /* Changer name */
131       0, 0, 0,                  /* append, read, num_writers */
132       0, 0, 0,                  /* is_open, is_labeled, offline */
133       0, 0,                     /* reserved, max_writers */
134       0,                        /* Autoselect */
135       changer->device->size(),  /* Number of devices */
136       "0",                      /* PoolId */
137       "*",                      /* ChangerName */
138       MediaType.c_str(),        /* MediaType */
139       "*");                     /* VolName */
140    Dmsg1(100, ">dird: %s\n", dir->msg);
141    return ok;
142 }
143 #endif
144
145
146 /*
147  * Send current JobStatus to Director
148  */
149 bool dir_send_job_status(JCR *jcr)
150 {
151    return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
152 }
153
154 /*
155  * Common routine for:
156  *   dir_get_volume_info()
157  * and
158  *   dir_find_next_appendable_volume()
159  *
160  *  NOTE!!! All calls to this routine must be protected by
161  *          locking vol_info_mutex before calling it so that
162  *          we don't have one thread modifying the parameters
163  *          and another reading them.
164  *
165  *  Returns: true  on success and vol info in dcr->VolCatInfo
166  *           false on failure
167  */
168 static bool do_get_volume_info(DCR *dcr)
169 {
170     JCR *jcr = dcr->jcr;
171     BSOCK *dir = jcr->dir_bsock;
172     VOLUME_CAT_INFO vol;
173     int n;
174     int32_t InChanger;
175
176     if (dir->recv() <= 0) {
177        Dmsg0(200, "getvolname error bnet_recv\n");
178        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
179        return false;
180     }
181     memset(&vol, 0, sizeof(vol));
182     Dmsg1(100, "<dird %s\n", dir->msg);
183     n = sscanf(dir->msg, OK_media, vol.VolCatName,
184                &vol.VolCatJobs, &vol.VolCatFiles,
185                &vol.VolCatBlocks, &vol.VolCatBytes,
186                &vol.VolCatMounts, &vol.VolCatErrors,
187                &vol.VolCatWrites, &vol.VolCatMaxBytes,
188                &vol.VolCatCapacityBytes, vol.VolCatStatus,
189                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
190                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
191                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
192                &vol.LabelType, &vol.VolMediaId);
193     if (n != 22) {
194        Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg);
195        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
196        return false;
197     }
198     vol.InChanger = InChanger;        /* bool in structure */
199     unbash_spaces(vol.VolCatName);
200     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
201     dcr->VolCatInfo = vol;            /* structure assignment */
202
203     Dmsg2(100, "do_reqest_vol_info return true slot=%d Volume=%s\n",
204           vol.Slot, 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     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
226     bash_spaces(dcr->VolCatInfo.VolCatName);
227     dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
228        writing==GET_VOL_INFO_FOR_WRITE?1:0);
229     Dmsg1(100, ">dird: %s\n", dir->msg);
230     unbash_spaces(dcr->VolCatInfo.VolCatName);
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->volume_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 found = false;
255
256     Dmsg0(200, "dir_find_next_appendable_volume\n");
257     /*
258      * Try the twenty oldest or most available volumes.  Note,
259      *   the most available could already be mounted on another
260      *   drive, so we continue looking for a not in use Volume.
261      */
262     lock_reservations();
263     P(vol_info_mutex);
264     dcr->volume_in_use = false;
265     for (int vol_index=1;  vol_index < 20; vol_index++) {
266        bash_spaces(dcr->media_type);
267        bash_spaces(dcr->pool_name);
268        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
269        unbash_spaces(dcr->media_type);
270        unbash_spaces(dcr->pool_name);
271        Dmsg1(100, ">dird: %s", dir->msg);
272        bool ok = do_get_volume_info(dcr);
273        if (ok) {
274           if (!is_volume_in_use(dcr)) {
275              found = true;
276              break;
277           } else {
278              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
279              dcr->volume_in_use = true;
280              continue;
281           }
282        } else {
283           Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
284              dcr->dev->print_name());
285           found = false;
286           break;
287        }
288     }
289     if (found) {
290        Dmsg0(400, "dir_find_next_appendable_volume return true\n");
291        if (reserve_volume(dcr, dcr->VolumeName) == 0) {
292           Dmsg2(100, "Could not reserve volume %s on %s\n", dcr->VolumeName,
293               dcr->dev->print_name());
294           goto bail_out;
295        }
296        V(vol_info_mutex);
297        unlock_reservations();
298        return true;
299     }
300
301 bail_out:
302     dcr->VolumeName[0] = 0;
303     V(vol_info_mutex);
304     unlock_reservations();
305     return false;
306 }
307
308
309 /*
310  * After writing a Volume, send the updated statistics
311  * back to the director. The information comes from the
312  * dev record.
313  */
314 bool dir_update_volume_info(DCR *dcr, bool label)
315 {
316    JCR *jcr = dcr->jcr;
317    BSOCK *dir = jcr->dir_bsock;
318    DEVICE *dev = dcr->dev;
319    time_t LastWritten = time(NULL);
320    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
321    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
322    int InChanger;
323    bool ok = false;
324    POOL_MEM VolumeName;
325
326    /* If system job, do not update catalog */
327    if (jcr->JobType == JT_SYSTEM) {
328       return true;
329    }
330
331    if (vol->VolCatName[0] == 0) {
332       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
333       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
334       return false;
335    }
336
337    /* Lock during Volume update */
338    P(vol_info_mutex);
339    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
340    /* Just labeled or relabeled the tape */
341    if (label) {
342       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
343    }
344    pm_strcpy(VolumeName, vol->VolCatName);
345    bash_spaces(VolumeName);
346    InChanger = vol->InChanger;
347    bnet_fsend(dir, Update_media, jcr->Job,
348       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
349       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
350       vol->VolCatMounts, vol->VolCatErrors,
351       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
352       LastWritten, vol->VolCatStatus, vol->Slot, label,
353       InChanger,                      /* bool in structure */
354       edit_int64(vol->VolReadTime, ed3),
355       edit_int64(vol->VolWriteTime, ed4),
356       edit_uint64(vol->VolFirstWritten, ed5),
357       vol->VolCatParts);
358     Dmsg1(100, ">dird: %s", dir->msg);
359
360    /* Do not lock device here because it may be locked from label */
361    if (!do_get_volume_info(dcr)) {
362       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
363       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
364          vol->VolCatName, jcr->errmsg);
365       goto bail_out;
366    }
367    Dmsg1(420, "get_volume_info(): %s", dir->msg);
368    /* Update dev Volume info in case something changed (e.g. expired) */
369    dev->VolCatInfo = dcr->VolCatInfo;
370    ok = true;
371
372 bail_out:
373    V(vol_info_mutex);
374    return ok;
375 }
376
377 /*
378  * After writing a Volume, create the JobMedia record.
379  */
380 bool dir_create_jobmedia_record(DCR *dcr)
381 {
382    JCR *jcr = dcr->jcr;
383    BSOCK *dir = jcr->dir_bsock;
384    char ed1[50];
385
386    /* If system job, do not update catalog */
387    if (jcr->JobType == JT_SYSTEM) {
388       return true;
389    }
390
391    if (!dcr->WroteVol) {
392       return true;                    /* nothing written to tape */
393    }
394
395    dcr->WroteVol = false;
396    bnet_fsend(dir, Create_job_media, jcr->Job,
397       dcr->VolFirstIndex, dcr->VolLastIndex,
398       dcr->StartFile, dcr->EndFile,
399       dcr->StartBlock, dcr->EndBlock, 
400       dcr->Copy, dcr->Stripe, 
401       edit_uint64(dcr->dev->VolCatInfo.VolMediaId, ed1));
402     Dmsg1(100, ">dird: %s", dir->msg);
403    if (bnet_recv(dir) <= 0) {
404       Dmsg0(190, "create_jobmedia error bnet_recv\n");
405       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
406            bnet_strerror(dir));
407       return false;
408    }
409    Dmsg1(100, "<dir: %s", dir->msg);
410    if (strcmp(dir->msg, OK_create) != 0) {
411       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
412       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
413       return false;
414    }
415    return true;
416 }
417
418
419 /*
420  * Update File Attribute data
421  */
422 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
423 {
424    JCR *jcr = dcr->jcr;
425    BSOCK *dir = jcr->dir_bsock;
426    ser_declare;
427
428 #ifdef NO_ATTRIBUTES_TEST
429    return true;
430 #endif
431
432    dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
433    dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
434                 sizeof(DEV_RECORD) + rec->data_len);
435    ser_begin(dir->msg + dir->msglen, 0);
436    ser_uint32(rec->VolSessionId);
437    ser_uint32(rec->VolSessionTime);
438    ser_int32(rec->FileIndex);
439    ser_int32(rec->Stream);
440    ser_uint32(rec->data_len);
441    ser_bytes(rec->data, rec->data_len);
442    dir->msglen = ser_length(dir->msg);
443    Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
444    return bnet_send(dir);
445 }
446
447
448 /*
449  *   Request the sysop to create an appendable volume
450  *
451  *   Entered with device blocked.
452  *   Leaves with device blocked.
453  *
454  *   Returns: true  on success (operator issues a mount command)
455  *            false on failure
456  *              Note, must create dev->errmsg on error return.
457  *
458  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
459  *      information on suggested volume, but this may not be the
460  *      same as what is actually mounted.
461  *
462  *    When we return with success, the correct tape may or may not
463  *      actually be mounted. The calling routine must read it and
464  *      verify the label.
465  */
466 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
467 {
468    int stat = W_TIMEOUT;
469    DEVICE *dev = dcr->dev;
470    JCR *jcr = dcr->jcr;
471    bool got_vol = false;
472
473    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
474    ASSERT(dev->blocked());
475    for ( ;; ) {
476       if (job_canceled(jcr)) {
477          Mmsg(dev->errmsg,
478               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
479               jcr->Job, dev->print_name());
480          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
481          return false;
482       }
483       dev->dlock();  
484       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
485       dev->dunlock();
486       if (got_vol) {
487          return true;
488       } else {
489          if (stat == W_TIMEOUT || stat == W_MOUNT) {
490             Jmsg(jcr, M_MOUNT, 0, _(
491 "Job %s waiting. Cannot find any appendable volumes.\n"
492 "Please use the \"label\"  command to create a new Volume for:\n"
493 "    Storage:      %s\n"
494 "    Pool:         %s\n"
495 "    Media type:   %s\n"),
496                jcr->Job,
497                dev->print_name(),
498                dcr->pool_name,
499                dcr->media_type);
500          }
501       }
502
503       set_jcr_job_status(jcr, JS_WaitMedia);
504       dir_send_job_status(jcr);
505
506       stat = wait_for_sysop(dcr);
507       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
508       if (dev->poll) {
509          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
510          continue;
511       }
512
513       if (stat == W_TIMEOUT) {
514          if (!double_dev_wait_time(dev)) {
515             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
516                dev->print_name(), jcr->Job);
517             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
518             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
519             return false;             /* exceeded maximum waits */
520          }
521          continue;
522       }
523       if (stat == W_ERROR) {
524          berrno be;
525          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
526          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
527          return false;
528       }
529       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
530    }
531    set_jcr_job_status(jcr, JS_Running);
532    dir_send_job_status(jcr);
533    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
534    return true;
535 }
536
537 /*
538  *   Request to mount specific Volume
539  *
540  *   Entered with device blocked and dcr->VolumeName is desired
541  *      volume.
542  *   Leaves with device blocked.
543  *
544  *   Returns: true  on success (operator issues a mount command)
545  *            false on failure
546  *                  Note, must create dev->errmsg on error return.
547  *
548  */
549 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
550 {
551    int stat = W_TIMEOUT;
552    DEVICE *dev = dcr->dev;
553    JCR *jcr = dcr->jcr;
554
555    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
556    if (!dcr->VolumeName[0]) {
557       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
558       return false;
559    }
560    ASSERT(dev->blocked());
561    for ( ;; ) {
562       if (job_canceled(jcr)) {
563          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
564               jcr->Job, dev->print_name());
565          return false;
566       }
567
568       if (dev->is_dvd()) {   
569          dev->unmount(0);
570       }
571       
572       /*
573        * If we are not polling, and the wait timeout or the
574        *   user explicitly did a mount, send him the message.
575        *   Otherwise skip it.
576        */
577       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
578          Jmsg(jcr, M_MOUNT, 0, _("Please mount Volume \"%s\" or label a new one for:\n"
579               "    Job:          %s\n"
580               "    Storage:      %s\n"
581               "    Pool:         %s\n"
582               "    Media type:   %s\n"),
583               dcr->VolumeName,
584               jcr->Job,
585               dev->print_name(),
586               dcr->pool_name,
587               dcr->media_type);
588          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
589                dcr->VolumeName, dev->print_name(), jcr->Job);
590       }
591
592       set_jcr_job_status(jcr, JS_WaitMount);
593       dir_send_job_status(jcr);
594
595       stat = wait_for_sysop(dcr);          /* wait on device */
596       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
597       if (dev->poll) {
598          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
599          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
600          goto bail_out;
601       }
602
603       if (stat == W_TIMEOUT) {
604          if (!double_dev_wait_time(dev)) {
605             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
606                dev->print_name(), jcr->Job);
607             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
608             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
609             return false;             /* exceeded maximum waits */
610          }
611          continue;
612       }
613       if (stat == W_ERROR) {
614          berrno be;
615          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
616          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
617          return false;
618       }
619       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
620       break;
621    }
622
623 bail_out:
624    set_jcr_job_status(jcr, JS_Running);
625    dir_send_job_status(jcr);
626    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
627    return true;
628 }