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