]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
- Attempt to fix DVD writing by eliminating a number of 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    Copyright (C) 2000-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as ammended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"                   /* pull in global headers */
25 #include "stored.h"                   /* pull in Storage Deamon headers */
26
27 /* Requests sent to the Director */
28 static char Find_media[]   = "CatReq Job=%s FindMedia=%d pool_name=%s media_type=%s\n";
29 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
30 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
31    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
32    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
33    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
34    " VolParts=%u\n";
35 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
36    " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
37    " StartBlock=%u EndBlock=%u Copy=%d Strip=%d\n";
38 static char FileAttributes[] = "UpdCat Job=%s FileAttributes ";
39 static char Job_status[]     = "Status Job=%s JobStatus=%d\n";
40
41
42
43 /* Responses received from the Director */
44 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u"
45    " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u"
46    " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s"
47    " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d"
48    " VolReadTime=%" lld " VolWriteTime=%" lld " EndFile=%u EndBlock=%u"
49    " VolParts=%u LabelType=%d";
50
51
52 static char OK_create[] = "1000 OK CreateJobMedia\n";
53
54 #ifdef needed
55
56 static char Device_update[] = "DevUpd Job=%s device=%s "
57    "append=%d read=%d num_writers=%d "
58    "open=%d labeled=%d offline=%d "
59    "reserved=%d max_writers=%d "
60    "autoselect=%d autochanger=%d "
61    "changer_name=%s media_type=%s volume_name=%s\n";
62
63
64 /* Send update information about a device to Director */
65 bool dir_update_device(JCR *jcr, DEVICE *dev)
66 {
67    BSOCK *dir = jcr->dir_bsock;
68    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
69    DEVRES *device = dev->device;
70    bool ok;
71    
72    pm_strcpy(dev_name, device->hdr.name);
73    bash_spaces(dev_name);
74    if (dev->is_labeled()) {
75       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
76    } else {
77       pm_strcpy(VolumeName, "*");
78    }
79    bash_spaces(VolumeName);
80    pm_strcpy(MediaType, device->media_type);
81    bash_spaces(MediaType);
82    if (device->changer_res) {
83       pm_strcpy(ChangerName, device->changer_res->hdr.name);
84       bash_spaces(ChangerName);
85    } else {
86       pm_strcpy(ChangerName, "*");
87    }
88    ok =bnet_fsend(dir, Device_update, 
89       jcr->Job,
90       dev_name.c_str(),
91       dev->can_append()!=0,
92       dev->can_read()!=0, dev->num_writers, 
93       dev->is_open()!=0, dev->is_labeled()!=0,
94       dev->is_offline()!=0, dev->reserved_device, 
95       dev->is_tape()?100000:1,
96       dev->autoselect, 0, 
97       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
98    Dmsg1(100, ">dird: %s\n", dir->msg);
99    return ok;
100 }
101
102 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
103 {
104    BSOCK *dir = jcr->dir_bsock;
105    POOL_MEM dev_name, MediaType;
106    DEVRES *device;
107    bool ok;
108
109    pm_strcpy(dev_name, changer->hdr.name);
110    bash_spaces(dev_name);
111    device = (DEVRES *)changer->device->first();
112    pm_strcpy(MediaType, device->media_type);
113    bash_spaces(MediaType);
114    /* This is mostly to indicate that we are here */
115    ok = bnet_fsend(dir, Device_update,
116       jcr->Job,
117       dev_name.c_str(),         /* Changer name */
118       0, 0, 0,                  /* append, read, num_writers */
119       0, 0, 0,                  /* is_open, is_labeled, offline */
120       0, 0,                     /* reserved, max_writers */
121       0,                        /* Autoselect */
122       changer->device->size(),  /* Number of devices */
123       "0",                      /* PoolId */
124       "*",                      /* ChangerName */
125       MediaType.c_str(),        /* MediaType */
126       "*");                     /* VolName */
127    Dmsg1(100, ">dird: %s\n", dir->msg);
128    return ok;
129 }
130 #endif
131
132
133 /*
134  * Send current JobStatus to Director
135  */
136 bool dir_send_job_status(JCR *jcr)
137 {
138    return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
139 }
140
141 /*
142  * Common routine for:
143  *   dir_get_volume_info()
144  * and
145  *   dir_find_next_appendable_volume()
146  *
147  *  Returns: true  on success and vol info in dcr->VolCatInfo
148  *           false on failure
149  */
150 static bool do_get_volume_info(DCR *dcr)
151 {
152     JCR *jcr = dcr->jcr;
153     BSOCK *dir = jcr->dir_bsock;
154     VOLUME_CAT_INFO vol;
155     int n;
156     int InChanger;
157
158     dcr->VolumeName[0] = 0;           /* No volume */
159     if (bnet_recv(dir) <= 0) {
160        Dmsg0(200, "getvolname error bnet_recv\n");
161        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
162        return false;
163     }
164     memset(&vol, 0, sizeof(vol));
165     Dmsg1(100, "<dird %s", dir->msg);
166     n = sscanf(dir->msg, OK_media, vol.VolCatName,
167                &vol.VolCatJobs, &vol.VolCatFiles,
168                &vol.VolCatBlocks, &vol.VolCatBytes,
169                &vol.VolCatMounts, &vol.VolCatErrors,
170                &vol.VolCatWrites, &vol.VolCatMaxBytes,
171                &vol.VolCatCapacityBytes, vol.VolCatStatus,
172                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
173                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
174                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
175                &vol.LabelType);
176     if (n != 21) {
177        Dmsg2(100, "Bad response from Dir fields=%d: %s\n", n, dir->msg);
178        Mmsg(jcr->errmsg, _("Error getting Volume info: %s\n"), dir->msg);
179        return false;
180     }
181     vol.InChanger = InChanger;        /* bool in structure */
182     unbash_spaces(vol.VolCatName);
183     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
184     memcpy(&dcr->VolCatInfo, &vol, sizeof(dcr->VolCatInfo));
185
186    /* ***FIXME*** we really should not do this but must for the moment */
187    if (dcr->dev->num_parts < dcr->VolCatInfo.VolCatParts) {
188       dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts;
189    }
190
191     Dmsg2(300, "do_reqest_vol_info got slot=%d Volume=%s\n",
192           vol.Slot, vol.VolCatName);
193     return true;
194 }
195
196
197 /*
198  * Get Volume info for a specific volume from the Director's Database
199  *
200  * Returns: true  on success   (Director guarantees that Pool and MediaType
201  *                              are correct and VolStatus==Append or
202  *                              VolStatus==Recycle)
203  *          false on failure
204  *
205  *          Volume information returned in dcr->VolCatInfo
206  */
207 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
208 {
209     JCR *jcr = dcr->jcr;
210     BSOCK *dir = jcr->dir_bsock;
211
212     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
213     bash_spaces(dcr->VolCatInfo.VolCatName);
214     bnet_fsend(dir, Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
215        writing==GET_VOL_INFO_FOR_WRITE?1:0);
216     Dmsg1(100, ">dird: %s", dir->msg);
217     return do_get_volume_info(dcr);
218 }
219
220 /*
221  * Get info on the next appendable volume in the Director's database
222  * Returns: true  on success
223  *          false on failure
224  *
225  *          Volume information returned in dcr
226  *
227  */
228 bool dir_find_next_appendable_volume(DCR *dcr)
229 {
230     JCR *jcr = dcr->jcr;
231     BSOCK *dir = jcr->dir_bsock;
232     bool found = false;
233
234     Dmsg0(200, "dir_find_next_appendable_volume\n");
235     /*
236      * Try the twenty oldest or most available volumes.  Note,
237      *   the most available could already be mounted on another
238      *   drive, so we continue looking for a not in use Volume.
239      */
240     for (int vol_index=1;  vol_index < 20; vol_index++) {
241        bash_spaces(dcr->media_type);
242        bash_spaces(dcr->pool_name);
243        bnet_fsend(dir, Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
244        unbash_spaces(dcr->media_type);
245        unbash_spaces(dcr->pool_name);
246        Dmsg1(100, ">dird: %s", dir->msg);
247        if (do_get_volume_info(dcr)) {
248           if (is_volume_in_use(dcr->VolumeName)) {
249              continue;
250           } else {
251              found = true;
252              break;
253           }
254        } else {
255           Dmsg0(200, "No volume info, return false\n");
256           return false;
257        }
258     }
259     if (found) {
260        Dmsg0(400, "dir_find_next_appendable_volume return true\n");
261        new_volume(dcr->VolumeName, NULL);   /* reserve volume */
262        return true;
263     }
264     return false;
265 }
266
267
268 /*
269  * After writing a Volume, send the updated statistics
270  * back to the director. The information comes from the
271  * dev record.
272  */
273 bool dir_update_volume_info(DCR *dcr, bool label)
274 {
275    JCR *jcr = dcr->jcr;
276    BSOCK *dir = jcr->dir_bsock;
277    DEVICE *dev = dcr->dev;
278    time_t LastWritten = time(NULL);
279    char ed1[50], ed2[50], ed3[50], ed4[50];
280    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
281    int InChanger;
282    POOL_MEM VolumeName;
283
284    if (vol->VolCatName[0] == 0) {
285       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
286       Pmsg0(000, "NULL Volume name. This shouldn't happen!!!\n");
287       return false;
288    }
289    if (dev->can_read()) {
290       Jmsg0(jcr, M_FATAL, 0, _("Attempt to update_volume_info in read mode!!!\n"));
291       Pmsg0(000, "Attempt to update_volume_info in read mode!!!\n");
292       return false;
293    }
294
295    Dmsg1(300, "Update cat VolFiles=%d\n", dev->file);
296    /* Just labeled or relabeled the tape */
297    if (label) {
298       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
299       vol->VolCatBytes = 1;           /* indicates tape labeled */
300    }
301    pm_strcpy(VolumeName, vol->VolCatName);
302    bash_spaces(VolumeName);
303    InChanger = vol->InChanger;
304    bnet_fsend(dir, Update_media, jcr->Job,
305       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
306       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
307       vol->VolCatMounts, vol->VolCatErrors,
308       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
309       LastWritten, vol->VolCatStatus, vol->Slot, label,
310       InChanger,                      /* bool in structure */
311       edit_uint64(vol->VolReadTime, ed3),
312       edit_uint64(vol->VolWriteTime, ed4),
313       vol->VolCatParts);
314     Dmsg1(100, ">dird: %s", dir->msg);
315
316    if (!do_get_volume_info(dcr)) {
317       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
318       Pmsg2(000, "Didn't get vol info vol=%s: ERR=%s", 
319          vol->VolCatName, jcr->errmsg);
320       return false;
321    }
322    Dmsg1(420, "get_volume_info(): %s", dir->msg);
323    /* Update dev Volume info in case something changed (e.g. expired) */
324    memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
325    return true;
326 }
327
328 /*
329  * After writing a Volume, create the JobMedia record.
330  */
331 bool dir_create_jobmedia_record(DCR *dcr)
332 {
333    JCR *jcr = dcr->jcr;
334    BSOCK *dir = jcr->dir_bsock;
335
336    if (!dcr->WroteVol) {
337       return true;                    /* nothing written to tape */
338    }
339
340    dcr->WroteVol = false;
341    bnet_fsend(dir, Create_job_media, jcr->Job,
342       dcr->VolFirstIndex, dcr->VolLastIndex,
343       dcr->StartFile, dcr->EndFile,
344       dcr->StartBlock, dcr->EndBlock, 
345       dcr->Copy, dcr->Stripe);
346     Dmsg1(100, ">dird: %s", dir->msg);
347    if (bnet_recv(dir) <= 0) {
348       Dmsg0(190, "create_jobmedia error bnet_recv\n");
349       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
350            bnet_strerror(dir));
351       return false;
352    }
353    Dmsg1(100, "<dir: %s", dir->msg);
354    if (strcmp(dir->msg, OK_create) != 0) {
355       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
356       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
357       return false;
358    }
359    return true;
360 }
361
362
363 /*
364  * Update File Attribute data
365  */
366 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
367 {
368    JCR *jcr = dcr->jcr;
369    BSOCK *dir = jcr->dir_bsock;
370    ser_declare;
371
372 #ifdef NO_ATTRIBUTES_TEST
373    return true;
374 #endif
375
376    dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
377    dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
378                 sizeof(DEV_RECORD) + rec->data_len);
379    ser_begin(dir->msg + dir->msglen, 0);
380    ser_uint32(rec->VolSessionId);
381    ser_uint32(rec->VolSessionTime);
382    ser_int32(rec->FileIndex);
383    ser_int32(rec->Stream);
384    ser_uint32(rec->data_len);
385    ser_bytes(rec->data, rec->data_len);
386    dir->msglen = ser_length(dir->msg);
387    Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
388    return bnet_send(dir);
389 }
390
391
392 /*
393  *   Request the sysop to create an appendable volume
394  *
395  *   Entered with device blocked.
396  *   Leaves with device blocked.
397  *
398  *   Returns: true  on success (operator issues a mount command)
399  *            false on failure
400  *              Note, must create dev->errmsg on error return.
401  *
402  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
403  *      information on suggested volume, but this may not be the
404  *      same as what is actually mounted.
405  *
406  *    When we return with success, the correct tape may or may not
407  *      actually be mounted. The calling routine must read it and
408  *      verify the label.
409  */
410 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
411 {
412    int stat = 0, jstat;
413    bool unmounted;
414    bool first = true;
415    DEVICE *dev = dcr->dev;
416    JCR *jcr = dcr->jcr;
417
418    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
419    ASSERT(dev->dev_blocked);
420    for ( ;; ) {
421       if (job_canceled(jcr)) {
422          Mmsg(dev->errmsg,
423               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
424               jcr->Job, dev->print_name());
425          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
426          return false;
427       }
428       /* First pass, we *know* there are no appendable volumes, so no need to call */
429       if (!first && dir_find_next_appendable_volume(dcr)) { /* get suggested volume */
430          unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
431                      (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
432          /*
433           * If we have a valid volume name and we are not
434           *   removable media, return now, or if we have a
435           *   Slot for an autochanger, otherwise wait
436           *   for the operator to mount the media.
437           */
438          if (!unmounted && ((dcr->VolumeName[0] && !dev_cap(dev, CAP_REM) &&
439                 dev_cap(dev, CAP_LABEL)) ||
440                  (dcr->VolumeName[0] && dcr->VolCatInfo.Slot))) {
441             Dmsg0(400, "Return 1 from mount without wait.\n");
442             return true;
443          }
444          jstat = JS_WaitMount;
445          if (!dev->poll) {
446             Jmsg(jcr, M_MOUNT, 0, _(
447 "Please mount Volume \"%s\" on Storage Device %s for Job %s\n"
448 "Use \"mount\" command to release Job.\n"),
449               dcr->VolumeName, dev->print_name(), jcr->Job);
450             Dmsg3(400, "Mount %s on %s for Job %s\n",
451                   dcr->VolumeName, dcr->dev_name, jcr->Job);
452          }
453       } else {
454          jstat = JS_WaitMedia;
455          if (!dev->poll) {
456             Jmsg(jcr, M_MOUNT, 0, _(
457 "Job %s waiting. Cannot find any appendable volumes.\n"
458 "Please use the \"label\"  command to create a new Volume for:\n"
459 "    Storage:      %s\n"
460 "    Media type:   %s\n"
461 "    Pool:         %s\n"),
462                jcr->Job,
463                dev->print_name(),
464                dcr->media_type,
465                dcr->pool_name);
466          }
467       }
468       first = false;
469
470       jcr->JobStatus = jstat;
471       dir_send_job_status(jcr);
472
473       stat = wait_for_sysop(dcr);
474       if (dev->poll) {
475          Dmsg1(400, "Poll timeout in create append vol on device %s\n", dev->print_name());
476          continue;
477       }
478
479       if (stat == ETIMEDOUT) {
480          if (!double_dev_wait_time(dev)) {
481             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
482                dev->print_name(), jcr->Job);
483             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
484             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
485             return false;             /* exceeded maximum waits */
486          }
487          continue;
488       }
489       if (stat == EINVAL) {
490          berrno be;
491          Mmsg2(dev->errmsg, _("pthread error in mount_next_volume stat=%d ERR=%s\n"),
492                stat, be.strerror(stat));
493          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
494          return false;
495       }
496       if (stat != 0) {
497          berrno be;
498          Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
499             be.strerror(stat));
500       }
501       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
502
503       /* If no VolumeName, and cannot get one, try again */
504       if (dcr->VolumeName[0] == 0 && !job_canceled(jcr) &&
505           !dir_find_next_appendable_volume(dcr)) {
506          Jmsg(jcr, M_MOUNT, 0, _(
507 "Someone woke me up, but I cannot find any appendable\n"
508 "volumes for Job=%s.\n"), jcr->Job);
509          /* Restart wait counters after user interaction */
510          init_device_wait_timers(dcr);
511          continue;
512       }
513       unmounted = (dev->dev_blocked == BST_UNMOUNTED) ||
514                   (dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
515       if (unmounted) {
516          continue;                    /* continue to wait */
517       }
518
519       /*
520        * Device mounted, we have a volume, break and return
521        */
522       break;
523    }
524    set_jcr_job_status(jcr, JS_Running);
525    dir_send_job_status(jcr);
526    Dmsg0(400, "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 = 0;
545    const char *msg;
546    DEVICE *dev = dcr->dev;
547    JCR *jcr = dcr->jcr;
548
549    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
550    if (!dcr->VolumeName[0]) {
551       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
552       return false;
553    }
554    ASSERT(dev->dev_blocked);
555    for ( ;; ) {
556       if (job_canceled(jcr)) {
557          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
558               jcr->Job, dev->print_name());
559          return false;
560       }
561
562       if (!dev->poll) {
563          msg = _("Please mount");
564          Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device %s for Job %s\n"),
565               msg, dcr->VolumeName, dev->print_name(), jcr->Job);
566          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
567                dcr->VolumeName, dcr->dev_name, jcr->Job);
568       }
569
570       jcr->JobStatus = JS_WaitMount;
571       dir_send_job_status(jcr);
572
573       stat = wait_for_sysop(dcr);    ;     /* wait on device */
574       if (dev->poll) {
575          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
576          Dmsg1(400, "Blocked=%s\n", edit_blocked_reason(dev));
577          return true;
578       }
579
580       if (stat == ETIMEDOUT) {
581          if (!double_dev_wait_time(dev)) {
582             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
583                dev->print_name(), jcr->Job);
584             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
585             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
586             return false;             /* exceeded maximum waits */
587          }
588          continue;
589       }
590       if (stat == EINVAL) {
591          berrno be;
592          Mmsg2(dev->errmsg, _("pthread error in mount_volume stat=%d ERR=%s\n"),
593                stat, be.strerror(stat));
594          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
595          return false;
596       }
597       if (stat != 0) {
598          berrno be;
599          Jmsg(jcr, M_FATAL, 0, _("pthread error in mount_next_volume stat=%d: ERR=%s\n"), stat,
600             be.strerror(stat));
601       }
602       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
603       break;
604    }
605    set_jcr_job_status(jcr, JS_Running);
606    dir_send_job_status(jcr);
607    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
608    return true;
609 }