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