]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Apply SunOS patch for ACLs submitted by David Duchscher.
[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     Dmsg2(300, "do_reqest_vol_info return true slot=%d Volume=%s\n",
187           vol.Slot, vol.VolCatName);
188     return true;
189 }
190
191
192 /*
193  * Get Volume info for a specific volume from the Director's Database
194  *
195  * Returns: true  on success   (Director guarantees that Pool and MediaType
196  *                              are correct and VolStatus==Append or
197  *                              VolStatus==Recycle)
198  *          false on failure
199  *
200  *          Volume information returned in dcr->VolCatInfo
201  */
202 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
203 {
204     JCR *jcr = dcr->jcr;
205     BSOCK *dir = jcr->dir_bsock;
206
207     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
208     bash_spaces(dcr->VolCatInfo.VolCatName);
209     bnet_fsend(dir, Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
210        writing==GET_VOL_INFO_FOR_WRITE?1:0);
211     Dmsg1(100, ">dird: %s", dir->msg);
212     bool OK = do_get_volume_info(dcr);
213     return OK;
214 }
215
216 /*
217  * Get info on the next appendable volume in the Director's database
218  * Returns: true  on success
219  *          false on failure
220  *
221  *          Volume information returned in dcr
222  *
223  */
224 bool dir_find_next_appendable_volume(DCR *dcr)
225 {
226     JCR *jcr = dcr->jcr;
227     BSOCK *dir = jcr->dir_bsock;
228     bool found = false;
229
230     Dmsg0(200, "dir_find_next_appendable_volume\n");
231     /*
232      * Try the twenty oldest or most available volumes.  Note,
233      *   the most available could already be mounted on another
234      *   drive, so we continue looking for a not in use Volume.
235      */
236     for (int vol_index=1;  vol_index < 20; vol_index++) {
237        bash_spaces(dcr->media_type);
238        bash_spaces(dcr->pool_name);
239        bnet_fsend(dir, Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
240        unbash_spaces(dcr->media_type);
241        unbash_spaces(dcr->pool_name);
242        Dmsg1(100, ">dird: %s", dir->msg);
243        bool OK = do_get_volume_info(dcr);
244        if (OK) {
245           if (dcr->any_volume || !is_volume_in_use(dcr)) {
246              found = true;
247              break;
248           } else {
249              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
250              continue;
251           }
252        } else {
253           Dmsg0(200, "No volume info, return false\n");
254           return false;
255        }
256     }
257     if (found) {
258        Dmsg0(400, "dir_find_next_appendable_volume return true\n");
259        new_volume(dcr, dcr->VolumeName);   /* reserve volume */
260        return true;
261     }
262     dcr->VolumeName[0] = 0;
263     return false;
264 }
265
266
267 /*
268  * After writing a Volume, send the updated statistics
269  * back to the director. The information comes from the
270  * dev record.
271  */
272 bool dir_update_volume_info(DCR *dcr, bool label)
273 {
274    JCR *jcr = dcr->jcr;
275    BSOCK *dir = jcr->dir_bsock;
276    DEVICE *dev = dcr->dev;
277    time_t LastWritten = time(NULL);
278    char ed1[50], ed2[50], ed3[50], ed4[50];
279    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
280    int InChanger;
281    POOL_MEM VolumeName;
282
283    if (vol->VolCatName[0] == 0) {
284       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
285       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
286       return false;
287    }
288    if (dev->can_read()) {
289       Jmsg0(jcr, M_FATAL, 0, _("Attempt to update_volume_info in read mode!!!\n"));
290       Pmsg0(000, _("Attempt to update_volume_info in read mode!!!\n"));
291       return false;
292    }
293
294    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
295    /* Just labeled or relabeled the tape */
296    if (label) {
297       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
298       vol->VolCatBytes = 1;           /* indicates tape labeled */
299    }
300    pm_strcpy(VolumeName, vol->VolCatName);
301    bash_spaces(VolumeName);
302    InChanger = vol->InChanger;
303    bnet_fsend(dir, Update_media, jcr->Job,
304       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
305       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
306       vol->VolCatMounts, vol->VolCatErrors,
307       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
308       LastWritten, vol->VolCatStatus, vol->Slot, label,
309       InChanger,                      /* bool in structure */
310       edit_uint64(vol->VolReadTime, ed3),
311       edit_uint64(vol->VolWriteTime, ed4),
312       vol->VolCatParts);
313     Dmsg1(100, ">dird: %s", dir->msg);
314
315    /* Do not lock device here because it may be locked from label */
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    bool OK = false;
418
419    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
420    ASSERT(dev->dev_blocked);
421    for ( ;; ) {
422       if (job_canceled(jcr)) {
423          Mmsg(dev->errmsg,
424               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
425               jcr->Job, dev->print_name());
426          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
427          return false;
428       }
429       /* First pass, we *know* there are no appendable volumes, so no need to call */
430       if (!first) {
431          P(dev->mutex);
432          OK = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
433          V(dev->mutex);
434       }
435       if (!first && OK) {
436          unmounted = is_device_unmounted(dev);
437          /*
438           * If we have a valid volume name and we are not
439           *   removable media, return now, or if we have a
440           *   Slot for an autochanger, otherwise wait
441           *   for the operator to mount the media.
442           */
443          if (!unmounted && ((dcr->VolumeName[0] && !dev_cap(dev, CAP_REM) &&
444                 dev_cap(dev, CAP_LABEL)) ||
445                  (dcr->VolumeName[0] && dcr->VolCatInfo.Slot))) {
446             Dmsg0(400, "Return 1 from mount without wait.\n");
447             return true;
448          }
449          jstat = JS_WaitMount;
450          if (!dev->poll) {
451             Jmsg(jcr, M_MOUNT, 0, _(
452 "Please mount Volume \"%s\" on Storage Device %s for Job %s\n"
453 "Use \"mount\" command to release Job.\n"),
454               dcr->VolumeName, dev->print_name(), jcr->Job);
455             Dmsg3(400, "Mount %s on %s for Job %s\n",
456                   dcr->VolumeName, dcr->dev_name, jcr->Job);
457          }
458       } else {
459          jstat = JS_WaitMedia;
460          if (!dev->poll) {
461             Jmsg(jcr, M_MOUNT, 0, _(
462 "Job %s waiting. Cannot find any appendable volumes.\n"
463 "Please use the \"label\"  command to create a new Volume for:\n"
464 "    Storage:      %s\n"
465 "    Media type:   %s\n"
466 "    Pool:         %s\n"),
467                jcr->Job,
468                dev->print_name(),
469                dcr->media_type,
470                dcr->pool_name);
471          }
472       }
473       first = false;
474
475       jcr->JobStatus = jstat;
476       dir_send_job_status(jcr);
477
478       stat = wait_for_sysop(dcr);
479       if (dev->poll) {
480          Dmsg1(000, "Poll timeout in create append vol on device %s\n", dev->print_name());
481          continue;
482       }
483
484       if (stat == ETIMEDOUT) {
485          if (!double_dev_wait_time(dev)) {
486             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
487                dev->print_name(), jcr->Job);
488             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
489             Dmsg1(000, "Gave up waiting on device %s\n", dev->print_name());
490             return false;             /* exceeded maximum waits */
491          }
492          continue;
493       }
494       if (stat == EINVAL) {
495          berrno be;
496          Mmsg2(dev->errmsg, _("pthread error in mount_next_volume stat=%d ERR=%s\n"),
497                stat, be.strerror(stat));
498          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
499          return false;
500       }
501       if (stat != 0) {
502          berrno be;
503          Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
504             be.strerror(stat));
505       }
506       Dmsg1(000, "Someone woke me for device %s\n", dev->print_name());
507
508       /* If no VolumeName, and cannot get one, try again */
509       P(dev->mutex);
510       if (dcr->VolumeName[0] == 0 && !job_canceled(jcr) &&
511           !dir_find_next_appendable_volume(dcr)) {
512          V(dev->mutex);
513          Jmsg(jcr, M_MOUNT, 0, _(
514 "Someone woke me up, but I cannot find any appendable\n"
515 "volumes for Job=%s.\n"), jcr->Job);
516          /* Restart wait counters after user interaction */
517          init_device_wait_timers(dcr);
518          continue;
519       }
520       V(dev->mutex);
521       unmounted = is_device_unmounted(dev);
522       if (unmounted) {
523          Dmsg0(400, "Device is unmounted. Must wait.\n");
524          continue;                    /* continue to wait */
525       }
526
527       /*
528        * Device mounted, we have a volume, break and return
529        */
530       break;
531    }
532    set_jcr_job_status(jcr, JS_Running);
533    dir_send_job_status(jcr);
534    Dmsg0(000, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
535    return true;
536 }
537
538 /*
539  *   Request to mount specific Volume
540  *
541  *   Entered with device blocked and dcr->VolumeName is desired
542  *      volume.
543  *   Leaves with device blocked.
544  *
545  *   Returns: true  on success (operator issues a mount command)
546  *            false on failure
547  *                  Note, must create dev->errmsg on error return.
548  *
549  */
550 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
551 {
552    int stat = 0;
553    DEVICE *dev = dcr->dev;
554    JCR *jcr = dcr->jcr;
555
556    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
557    if (!dcr->VolumeName[0]) {
558       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
559       return false;
560    }
561    ASSERT(dev->dev_blocked);
562    for ( ;; ) {
563       if (job_canceled(jcr)) {
564          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
565               jcr->Job, dev->print_name());
566          return false;
567       }
568
569       if (dev->is_dvd()) {   
570          unmount_dev(dev, 0);
571       }
572       if (!dev->poll) {
573          Jmsg(jcr, M_MOUNT, 0, _("Please mount Volume \"%s\" on Storage Device %s for Job %s\n"),
574               dcr->VolumeName, dev->print_name(), jcr->Job);
575          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
576                dcr->VolumeName, dev->print_name(), jcr->Job);
577       }
578
579       jcr->JobStatus = JS_WaitMount;
580       dir_send_job_status(jcr);
581
582       stat = wait_for_sysop(dcr);    ;     /* wait on device */
583       if (dev->poll) {
584          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
585          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
586          return true;
587       }
588
589       if (stat == ETIMEDOUT) {
590          if (!double_dev_wait_time(dev)) {
591             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
592                dev->print_name(), jcr->Job);
593             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
594             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
595             return false;             /* exceeded maximum waits */
596          }
597          continue;
598       }
599       if (stat == EINVAL) {
600          berrno be;
601          Mmsg2(dev->errmsg, _("pthread error in mount_volume stat=%d ERR=%s\n"),
602                stat, be.strerror(stat));
603          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
604          return false;
605       }
606       if (stat != 0) {
607          berrno be;
608          Jmsg(jcr, M_FATAL, 0, _("pthread error in mount_next_volume stat=%d: ERR=%s\n"), stat,
609             be.strerror(stat));
610       }
611       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
612       break;
613    }
614    set_jcr_job_status(jcr, JS_Running);
615    dir_send_job_status(jcr);
616    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
617    return true;
618 }