]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
kes Fix dird/ua_cmds.c so that a cancel command checks if the
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2  *  Subroutines to handle Catalog reqests sent to the Director
3  *   Reqests/commands from the Director are handled in dircmd.c
4  *
5  *   Kern Sibbald, December 2000
6  *
7  *   Version $Id$
8  */
9 /*
10    Bacula® - The Network Backup Solution
11
12    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
13
14    The main author of Bacula is Kern Sibbald, with contributions from
15    many others, a complete list can be found in the file AUTHORS.
16    This program is Free Software; you can redistribute it and/or
17    modify it under the terms of version two of the GNU General Public
18    License as published by the Free Software Foundation plus additions
19    that are listed in the file LICENSE.
20
21    This program is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24    General Public License for more details.
25
26    You should have received a copy of the GNU General Public License
27    along with this program; if not, write to the Free Software
28    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29    02110-1301, USA.
30
31    Bacula® is a registered trademark of John Walker.
32    The licensor of Bacula is the Free Software Foundation Europe
33    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34    Switzerland, email:ftf@fsfeurope.org.
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 (bnet_recv(dir) <= 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", 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        Dmsg2(100, "Bad response from Dir fields=%d: %s", n, 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     bnet_fsend(dir, Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
228        writing==GET_VOL_INFO_FOR_WRITE?1:0);
229     Dmsg1(100, ">dird: %s", 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  * Returns: true  on success
241  *          false on failure
242  *
243  *          Volume information returned in dcr
244  *
245  */
246 bool dir_find_next_appendable_volume(DCR *dcr)
247 {
248     JCR *jcr = dcr->jcr;
249     BSOCK *dir = jcr->dir_bsock;
250     bool found = false;
251
252     Dmsg0(200, "dir_find_next_appendable_volume\n");
253     /*
254      * Try the twenty oldest or most available volumes.  Note,
255      *   the most available could already be mounted on another
256      *   drive, so we continue looking for a not in use Volume.
257      */
258     lock_reservations();
259     P(vol_info_mutex);
260     for (int vol_index=1;  vol_index < 20; vol_index++) {
261        bash_spaces(dcr->media_type);
262        bash_spaces(dcr->pool_name);
263        bnet_fsend(dir, Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
264        unbash_spaces(dcr->media_type);
265        unbash_spaces(dcr->pool_name);
266        Dmsg1(100, ">dird: %s", dir->msg);
267        bool ok = do_get_volume_info(dcr);
268        if (ok) {
269           if (dcr->any_volume || !is_volume_in_use(dcr)) {
270              found = true;
271              break;
272           } else {
273              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
274              continue;
275           }
276        } else {
277           Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
278              dcr->dev->print_name());
279           found = false;
280           break;
281        }
282     }
283     if (found) {
284        Dmsg0(400, "dir_find_next_appendable_volume return true\n");
285        new_volume(dcr, dcr->VolumeName);   /* reserve volume */
286        V(vol_info_mutex);
287        unlock_reservations();
288        return true;
289     }
290     dcr->VolumeName[0] = 0;
291     V(vol_info_mutex);
292     unlock_reservations();
293     return false;
294 }
295
296
297 /*
298  * After writing a Volume, send the updated statistics
299  * back to the director. The information comes from the
300  * dev record.
301  */
302 bool dir_update_volume_info(DCR *dcr, bool label)
303 {
304    JCR *jcr = dcr->jcr;
305    BSOCK *dir = jcr->dir_bsock;
306    DEVICE *dev = dcr->dev;
307    time_t LastWritten = time(NULL);
308    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
309    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
310    int InChanger;
311    bool ok = false;
312    POOL_MEM VolumeName;
313
314    /* If system job, do not update catalog */
315    if (jcr->JobType == JT_SYSTEM) {
316       return true;
317    }
318
319    if (vol->VolCatName[0] == 0) {
320       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
321       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
322       return false;
323    }
324    if (dev->can_read()) {
325       Jmsg0(jcr, M_FATAL, 0, _("Attempt to update_volume_info in read mode!!!\n"));
326       Pmsg0(000, _("Attempt to update_volume_info in read mode!!!\n"));
327       return false;
328    }
329
330    /* Lock during Volume update */
331    P(vol_info_mutex);
332    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
333    /* Just labeled or relabeled the tape */
334    if (label) {
335       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
336    }
337    pm_strcpy(VolumeName, vol->VolCatName);
338    bash_spaces(VolumeName);
339    InChanger = vol->InChanger;
340    bnet_fsend(dir, Update_media, jcr->Job,
341       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
342       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
343       vol->VolCatMounts, vol->VolCatErrors,
344       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
345       LastWritten, vol->VolCatStatus, vol->Slot, label,
346       InChanger,                      /* bool in structure */
347       edit_uint64(vol->VolReadTime, ed3),
348       edit_uint64(vol->VolWriteTime, ed4),
349       edit_uint64(vol->VolFirstWritten, ed5),
350       vol->VolCatParts);
351     Dmsg1(100, ">dird: %s", dir->msg);
352
353    /* Do not lock device here because it may be locked from label */
354    if (!do_get_volume_info(dcr)) {
355       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
356       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
357          vol->VolCatName, jcr->errmsg);
358       goto bail_out;
359    }
360    Dmsg1(420, "get_volume_info(): %s", dir->msg);
361    /* Update dev Volume info in case something changed (e.g. expired) */
362    dev->VolCatInfo = dcr->VolCatInfo;
363    ok = true;
364
365 bail_out:
366    V(vol_info_mutex);
367    return ok;
368 }
369
370 /*
371  * After writing a Volume, create the JobMedia record.
372  */
373 bool dir_create_jobmedia_record(DCR *dcr)
374 {
375    JCR *jcr = dcr->jcr;
376    BSOCK *dir = jcr->dir_bsock;
377    char ed1[50];
378
379    /* If system job, do not update catalog */
380    if (jcr->JobType == JT_SYSTEM) {
381       return true;
382    }
383
384    if (!dcr->WroteVol) {
385       return true;                    /* nothing written to tape */
386    }
387
388    dcr->WroteVol = false;
389    bnet_fsend(dir, Create_job_media, jcr->Job,
390       dcr->VolFirstIndex, dcr->VolLastIndex,
391       dcr->StartFile, dcr->EndFile,
392       dcr->StartBlock, dcr->EndBlock, 
393       dcr->Copy, dcr->Stripe, 
394       edit_uint64(dcr->dev->VolCatInfo.VolMediaId, ed1));
395     Dmsg1(100, ">dird: %s", dir->msg);
396    if (bnet_recv(dir) <= 0) {
397       Dmsg0(190, "create_jobmedia error bnet_recv\n");
398       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
399            bnet_strerror(dir));
400       return false;
401    }
402    Dmsg1(100, "<dir: %s", dir->msg);
403    if (strcmp(dir->msg, OK_create) != 0) {
404       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
405       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
406       return false;
407    }
408    return true;
409 }
410
411
412 /*
413  * Update File Attribute data
414  */
415 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
416 {
417    JCR *jcr = dcr->jcr;
418    BSOCK *dir = jcr->dir_bsock;
419    ser_declare;
420
421 #ifdef NO_ATTRIBUTES_TEST
422    return true;
423 #endif
424
425    dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
426    dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
427                 sizeof(DEV_RECORD) + rec->data_len);
428    ser_begin(dir->msg + dir->msglen, 0);
429    ser_uint32(rec->VolSessionId);
430    ser_uint32(rec->VolSessionTime);
431    ser_int32(rec->FileIndex);
432    ser_int32(rec->Stream);
433    ser_uint32(rec->data_len);
434    ser_bytes(rec->data, rec->data_len);
435    dir->msglen = ser_length(dir->msg);
436    Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
437    return bnet_send(dir);
438 }
439
440
441 /*
442  *   Request the sysop to create an appendable volume
443  *
444  *   Entered with device blocked.
445  *   Leaves with device blocked.
446  *
447  *   Returns: true  on success (operator issues a mount command)
448  *            false on failure
449  *              Note, must create dev->errmsg on error return.
450  *
451  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
452  *      information on suggested volume, but this may not be the
453  *      same as what is actually mounted.
454  *
455  *    When we return with success, the correct tape may or may not
456  *      actually be mounted. The calling routine must read it and
457  *      verify the label.
458  */
459 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
460 {
461    int stat = W_TIMEOUT;
462    DEVICE *dev = dcr->dev;
463    JCR *jcr = dcr->jcr;
464    bool got_vol = false;
465
466    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
467    ASSERT(dev->dev_blocked);
468    for ( ;; ) {
469       if (job_canceled(jcr)) {
470          Mmsg(dev->errmsg,
471               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
472               jcr->Job, dev->print_name());
473          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
474          return false;
475       }
476       P(dev->mutex);
477       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
478       V(dev->mutex);
479       if (got_vol) {
480          return true;
481       } else {
482          if (stat == W_TIMEOUT || stat == W_MOUNT) {
483             Jmsg(jcr, M_MOUNT, 0, _(
484 "Job %s waiting. Cannot find any appendable volumes.\n"
485 "Please use the \"label\"  command to create a new Volume for:\n"
486 "    Storage:      %s\n"
487 "    Media type:   %s\n"
488 "    Pool:         %s\n"),
489                jcr->Job,
490                dev->print_name(),
491                dcr->media_type,
492                dcr->pool_name);
493          }
494       }
495
496       set_jcr_job_status(jcr, JS_WaitMedia);
497       dir_send_job_status(jcr);
498
499       stat = wait_for_sysop(dcr);
500       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
501       if (dev->poll) {
502          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
503          continue;
504       }
505
506       if (stat == W_TIMEOUT) {
507          if (!double_dev_wait_time(dev)) {
508             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
509                dev->print_name(), jcr->Job);
510             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
511             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
512             return false;             /* exceeded maximum waits */
513          }
514          continue;
515       }
516       if (stat == W_ERROR) {
517          berrno be;
518          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
519          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
520          return false;
521       }
522       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
523    }
524    set_jcr_job_status(jcr, JS_Running);
525    dir_send_job_status(jcr);
526    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
527    return true;
528 }
529
530 /*
531  *   Request to mount specific Volume
532  *
533  *   Entered with device blocked and dcr->VolumeName is desired
534  *      volume.
535  *   Leaves with device blocked.
536  *
537  *   Returns: true  on success (operator issues a mount command)
538  *            false on failure
539  *                  Note, must create dev->errmsg on error return.
540  *
541  */
542 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
543 {
544    int stat = W_TIMEOUT;
545    DEVICE *dev = dcr->dev;
546    JCR *jcr = dcr->jcr;
547
548    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
549    if (!dcr->VolumeName[0]) {
550       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
551       return false;
552    }
553    ASSERT(dev->dev_blocked);
554    for ( ;; ) {
555       if (job_canceled(jcr)) {
556          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
557               jcr->Job, dev->print_name());
558          return false;
559       }
560
561       if (dev->is_dvd()) {   
562          dev->unmount(0);
563       }
564       
565       /*
566        * If we are not polling, and the wait timeout or the
567        *   user explicitly did a mount, send him the message.
568        *   Otherwise skip it.
569        */
570       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
571          Jmsg(jcr, M_MOUNT, 0, _("Please mount Volume \"%s\" on Storage Device %s for Job %s\n"),
572               dcr->VolumeName, dev->print_name(), jcr->Job);
573          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
574                dcr->VolumeName, dev->print_name(), jcr->Job);
575       }
576
577       set_jcr_job_status(jcr, JS_WaitMount);
578       dir_send_job_status(jcr);
579
580       stat = wait_for_sysop(dcr);          /* wait on device */
581       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
582       if (dev->poll) {
583          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
584          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
585          return true;
586       }
587
588       if (stat == W_TIMEOUT) {
589          if (!double_dev_wait_time(dev)) {
590             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
591                dev->print_name(), jcr->Job);
592             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
593             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
594             return false;             /* exceeded maximum waits */
595          }
596          continue;
597       }
598       if (stat == W_ERROR) {
599          berrno be;
600          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
601          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
602          return false;
603       }
604       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
605       break;
606    }
607    set_jcr_job_status(jcr, JS_Running);
608    dir_send_job_status(jcr);
609    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
610    return true;
611 }