]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Minor modifications outside DVD functions.
[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 amended 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    Now done in dev.c:open_dvd_device
191    */
192
193     Dmsg2(300, "do_reqest_vol_info return true slot=%d Volume=%s\n",
194           vol.Slot, vol.VolCatName);
195     return true;
196 }
197
198
199 /*
200  * Get Volume info for a specific volume from the Director's Database
201  *
202  * Returns: true  on success   (Director guarantees that Pool and MediaType
203  *                              are correct and VolStatus==Append or
204  *                              VolStatus==Recycle)
205  *          false on failure
206  *
207  *          Volume information returned in dcr->VolCatInfo
208  */
209 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
210 {
211     JCR *jcr = dcr->jcr;
212     BSOCK *dir = jcr->dir_bsock;
213
214     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
215     bash_spaces(dcr->VolCatInfo.VolCatName);
216     bnet_fsend(dir, Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
217        writing==GET_VOL_INFO_FOR_WRITE?1:0);
218     Dmsg1(100, ">dird: %s", dir->msg);
219     bool OK = do_get_volume_info(dcr);
220     return OK;
221 }
222
223 /*
224  * Get info on the next appendable volume in the Director's database
225  * Returns: true  on success
226  *          false on failure
227  *
228  *          Volume information returned in dcr
229  *
230  */
231 bool dir_find_next_appendable_volume(DCR *dcr)
232 {
233     JCR *jcr = dcr->jcr;
234     BSOCK *dir = jcr->dir_bsock;
235     bool found = false;
236
237     Dmsg0(200, "dir_find_next_appendable_volume\n");
238     /*
239      * Try the twenty oldest or most available volumes.  Note,
240      *   the most available could already be mounted on another
241      *   drive, so we continue looking for a not in use Volume.
242      */
243     for (int vol_index=1;  vol_index < 20; vol_index++) {
244        bash_spaces(dcr->media_type);
245        bash_spaces(dcr->pool_name);
246        bnet_fsend(dir, Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
247        unbash_spaces(dcr->media_type);
248        unbash_spaces(dcr->pool_name);
249        Dmsg1(100, ">dird: %s", dir->msg);
250        bool OK = do_get_volume_info(dcr);
251        if (OK) {
252           if (is_volume_in_use(dcr)) {
253              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
254              continue;
255           } else {
256              found = true;
257              break;
258           }
259        } else {
260           Dmsg0(200, "No volume info, return false\n");
261           return false;
262        }
263     }
264     if (found) {
265        Dmsg0(400, "dir_find_next_appendable_volume return true\n");
266        new_volume(dcr, dcr->VolumeName);   /* reserve volume */
267        return true;
268     }
269     dcr->VolumeName[0] = 0;
270     return false;
271 }
272
273
274 /*
275  * After writing a Volume, send the updated statistics
276  * back to the director. The information comes from the
277  * dev record.
278  */
279 bool dir_update_volume_info(DCR *dcr, bool label)
280 {
281    JCR *jcr = dcr->jcr;
282    BSOCK *dir = jcr->dir_bsock;
283    DEVICE *dev = dcr->dev;
284    time_t LastWritten = time(NULL);
285    char ed1[50], ed2[50], ed3[50], ed4[50];
286    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
287    int InChanger;
288    POOL_MEM VolumeName;
289
290    if (vol->VolCatName[0] == 0) {
291       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
292       Pmsg0(000, "NULL Volume name. This shouldn't happen!!!\n");
293       return false;
294    }
295    if (dev->can_read()) {
296       Jmsg0(jcr, M_FATAL, 0, _("Attempt to update_volume_info in read mode!!!\n"));
297       Pmsg0(000, "Attempt to update_volume_info in read mode!!!\n");
298       return false;
299    }
300
301    Dmsg1(300, "Update cat VolFiles=%d\n", dev->file);
302    /* Just labeled or relabeled the tape */
303    if (label) {
304       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
305       vol->VolCatBytes = 1;           /* indicates tape labeled */
306    }
307    pm_strcpy(VolumeName, vol->VolCatName);
308    bash_spaces(VolumeName);
309    InChanger = vol->InChanger;
310    bnet_fsend(dir, Update_media, jcr->Job,
311       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
312       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
313       vol->VolCatMounts, vol->VolCatErrors,
314       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
315       LastWritten, vol->VolCatStatus, vol->Slot, label,
316       InChanger,                      /* bool in structure */
317       edit_uint64(vol->VolReadTime, ed3),
318       edit_uint64(vol->VolWriteTime, ed4),
319       vol->VolCatParts);
320     Dmsg1(100, ">dird: %s", dir->msg);
321
322    /* Do not lock device here because it may be locked from label */
323    if (!do_get_volume_info(dcr)) {
324       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
325       Pmsg2(000, "Didn't get vol info vol=%s: ERR=%s", 
326          vol->VolCatName, jcr->errmsg);
327       return false;
328    }
329    Dmsg1(420, "get_volume_info(): %s", dir->msg);
330    /* Update dev Volume info in case something changed (e.g. expired) */
331    memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
332    return true;
333 }
334
335 /*
336  * After writing a Volume, create the JobMedia record.
337  */
338 bool dir_create_jobmedia_record(DCR *dcr)
339 {
340    JCR *jcr = dcr->jcr;
341    BSOCK *dir = jcr->dir_bsock;
342
343    if (!dcr->WroteVol) {
344       return true;                    /* nothing written to tape */
345    }
346
347    dcr->WroteVol = false;
348    bnet_fsend(dir, Create_job_media, jcr->Job,
349       dcr->VolFirstIndex, dcr->VolLastIndex,
350       dcr->StartFile, dcr->EndFile,
351       dcr->StartBlock, dcr->EndBlock, 
352       dcr->Copy, dcr->Stripe);
353     Dmsg1(100, ">dird: %s", dir->msg);
354    if (bnet_recv(dir) <= 0) {
355       Dmsg0(190, "create_jobmedia error bnet_recv\n");
356       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
357            bnet_strerror(dir));
358       return false;
359    }
360    Dmsg1(100, "<dir: %s", dir->msg);
361    if (strcmp(dir->msg, OK_create) != 0) {
362       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
363       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
364       return false;
365    }
366    return true;
367 }
368
369
370 /*
371  * Update File Attribute data
372  */
373 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
374 {
375    JCR *jcr = dcr->jcr;
376    BSOCK *dir = jcr->dir_bsock;
377    ser_declare;
378
379 #ifdef NO_ATTRIBUTES_TEST
380    return true;
381 #endif
382
383    dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
384    dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
385                 sizeof(DEV_RECORD) + rec->data_len);
386    ser_begin(dir->msg + dir->msglen, 0);
387    ser_uint32(rec->VolSessionId);
388    ser_uint32(rec->VolSessionTime);
389    ser_int32(rec->FileIndex);
390    ser_int32(rec->Stream);
391    ser_uint32(rec->data_len);
392    ser_bytes(rec->data, rec->data_len);
393    dir->msglen = ser_length(dir->msg);
394    Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
395    return bnet_send(dir);
396 }
397
398
399 /*
400  *   Request the sysop to create an appendable volume
401  *
402  *   Entered with device blocked.
403  *   Leaves with device blocked.
404  *
405  *   Returns: true  on success (operator issues a mount command)
406  *            false on failure
407  *              Note, must create dev->errmsg on error return.
408  *
409  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
410  *      information on suggested volume, but this may not be the
411  *      same as what is actually mounted.
412  *
413  *    When we return with success, the correct tape may or may not
414  *      actually be mounted. The calling routine must read it and
415  *      verify the label.
416  */
417 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
418 {
419    int stat = 0, jstat;
420    bool unmounted;
421    bool first = true;
422    DEVICE *dev = dcr->dev;
423    JCR *jcr = dcr->jcr;
424    bool OK = false;
425
426    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
427    ASSERT(dev->dev_blocked);
428    for ( ;; ) {
429       if (job_canceled(jcr)) {
430          Mmsg(dev->errmsg,
431               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
432               jcr->Job, dev->print_name());
433          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
434          return false;
435       }
436       /* First pass, we *know* there are no appendable volumes, so no need to call */
437       if (!first) {
438          P(dev->mutex);
439          OK = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
440          V(dev->mutex);
441       }
442       if (!first && OK) {
443          unmounted = is_device_unmounted(dev);
444          /*
445           * If we have a valid volume name and we are not
446           *   removable media, return now, or if we have a
447           *   Slot for an autochanger, otherwise wait
448           *   for the operator to mount the media.
449           */
450          if (!unmounted && ((dcr->VolumeName[0] && !dev_cap(dev, CAP_REM) &&
451                 dev_cap(dev, CAP_LABEL)) ||
452                  (dcr->VolumeName[0] && dcr->VolCatInfo.Slot))) {
453             Dmsg0(400, "Return 1 from mount without wait.\n");
454             return true;
455          }
456          jstat = JS_WaitMount;
457          if (!dev->poll) {
458             Jmsg(jcr, M_MOUNT, 0, _(
459 "Please mount Volume \"%s\" on Storage Device %s for Job %s\n"
460 "Use \"mount\" command to release Job.\n"),
461               dcr->VolumeName, dev->print_name(), jcr->Job);
462             Dmsg3(400, "Mount %s on %s for Job %s\n",
463                   dcr->VolumeName, dcr->dev_name, jcr->Job);
464          }
465       } else {
466          jstat = JS_WaitMedia;
467          if (!dev->poll) {
468             Jmsg(jcr, M_MOUNT, 0, _(
469 "Job %s waiting. Cannot find any appendable volumes.\n"
470 "Please use the \"label\"  command to create a new Volume for:\n"
471 "    Storage:      %s\n"
472 "    Media type:   %s\n"
473 "    Pool:         %s\n"),
474                jcr->Job,
475                dev->print_name(),
476                dcr->media_type,
477                dcr->pool_name);
478          }
479       }
480       first = false;
481
482       jcr->JobStatus = jstat;
483       dir_send_job_status(jcr);
484
485       stat = wait_for_sysop(dcr);
486       if (dev->poll) {
487          Dmsg1(400, "Poll timeout in create append vol on device %s\n", dev->print_name());
488          continue;
489       }
490
491       if (stat == ETIMEDOUT) {
492          if (!double_dev_wait_time(dev)) {
493             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
494                dev->print_name(), jcr->Job);
495             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
496             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
497             return false;             /* exceeded maximum waits */
498          }
499          continue;
500       }
501       if (stat == EINVAL) {
502          berrno be;
503          Mmsg2(dev->errmsg, _("pthread error in mount_next_volume stat=%d ERR=%s\n"),
504                stat, be.strerror(stat));
505          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
506          return false;
507       }
508       if (stat != 0) {
509          berrno be;
510          Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
511             be.strerror(stat));
512       }
513       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
514
515       /* If no VolumeName, and cannot get one, try again */
516       P(dev->mutex);
517       if (dcr->VolumeName[0] == 0 && !job_canceled(jcr) &&
518           !dir_find_next_appendable_volume(dcr)) {
519          V(dev->mutex);
520          Jmsg(jcr, M_MOUNT, 0, _(
521 "Someone woke me up, but I cannot find any appendable\n"
522 "volumes for Job=%s.\n"), jcr->Job);
523          /* Restart wait counters after user interaction */
524          init_device_wait_timers(dcr);
525          continue;
526       }
527       V(dev->mutex);
528       unmounted = is_device_unmounted(dev);
529       if (unmounted) {
530          Dmsg0(400, "Device is unmounted. Must wait.\n");
531          continue;                    /* continue to wait */
532       }
533
534       /*
535        * Device mounted, we have a volume, break and return
536        */
537       break;
538    }
539    set_jcr_job_status(jcr, JS_Running);
540    dir_send_job_status(jcr);
541    Dmsg0(400, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
542    return true;
543 }
544
545 /*
546  *   Request to mount specific Volume
547  *
548  *   Entered with device blocked and dcr->VolumeName is desired
549  *      volume.
550  *   Leaves with device blocked.
551  *
552  *   Returns: true  on success (operator issues a mount command)
553  *            false on failure
554  *                  Note, must create dev->errmsg on error return.
555  *
556  */
557 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
558 {
559    int stat = 0;
560    const char *msg;
561    DEVICE *dev = dcr->dev;
562    JCR *jcr = dcr->jcr;
563
564    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
565    if (!dcr->VolumeName[0]) {
566       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
567       return false;
568    }
569    ASSERT(dev->dev_blocked);
570    for ( ;; ) {
571       if (job_canceled(jcr)) {
572          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
573               jcr->Job, dev->print_name());
574          return false;
575       }
576
577       if (!dev->poll) {
578          msg = _("Please mount");
579          Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device %s for Job %s\n"),
580               msg, dcr->VolumeName, dev->print_name(), jcr->Job);
581          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
582                dcr->VolumeName, dev->print_name(), jcr->Job);
583       }
584
585       jcr->JobStatus = JS_WaitMount;
586       dir_send_job_status(jcr);
587
588       stat = wait_for_sysop(dcr);    ;     /* wait on device */
589       if (dev->poll) {
590          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
591          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
592          return true;
593       }
594
595       if (stat == ETIMEDOUT) {
596          if (!double_dev_wait_time(dev)) {
597             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
598                dev->print_name(), jcr->Job);
599             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
600             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
601             return false;             /* exceeded maximum waits */
602          }
603          continue;
604       }
605       if (stat == EINVAL) {
606          berrno be;
607          Mmsg2(dev->errmsg, _("pthread error in mount_volume stat=%d ERR=%s\n"),
608                stat, be.strerror(stat));
609          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
610          return false;
611       }
612       if (stat != 0) {
613          berrno be;
614          Jmsg(jcr, M_FATAL, 0, _("pthread error in mount_next_volume stat=%d: ERR=%s\n"), stat,
615             be.strerror(stat));
616       }
617       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
618       break;
619    }
620    set_jcr_job_status(jcr, JS_Running);
621    dir_send_job_status(jcr);
622    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
623    return true;
624 }