]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Implement Plugin Directory and plugin events.
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Subroutines to handle Catalog reqests sent to the Director
30  *   Reqests/commands from the Director are handled in dircmd.c
31  *
32  *   Kern Sibbald, December 2000
33  *
34  *   Version $Id$
35  */
36
37 #include "bacula.h"                   /* pull in global headers */
38 #include "stored.h"                   /* pull in Storage Deamon headers */
39
40 /* Requests sent to the Director */
41 static char Find_media[]   = "CatReq Job=%s FindMedia=%d pool_name=%s media_type=%s\n";
42 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
43 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
44    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
45    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
46    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
47    " VolFirstWritten=%s VolParts=%u\n";
48 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
49    " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
50    " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%s\n";
51 static char FileAttributes[] = "UpdCat Job=%s FileAttributes ";
52 static char Job_status[]     = "Status Job=%s JobStatus=%d\n";
53
54 /* Responses received from the Director */
55 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
56    " VolBlocks=%lu VolBytes=%lld VolMounts=%lu VolErrors=%lu VolWrites=%lu"
57    " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s"
58    " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
59    " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
60    " VolParts=%lu LabelType=%ld MediaId=%lld\n";
61
62
63 static char OK_create[] = "1000 OK CreateJobMedia\n";
64
65 static pthread_mutex_t vol_info_mutex = PTHREAD_MUTEX_INITIALIZER;
66
67 #ifdef needed
68
69 static char Device_update[] = "DevUpd Job=%s device=%s "
70    "append=%d read=%d num_writers=%d "
71    "open=%d labeled=%d offline=%d "
72    "reserved=%d max_writers=%d "
73    "autoselect=%d autochanger=%d "
74    "changer_name=%s media_type=%s volume_name=%s\n";
75
76
77 /* Send update information about a device to Director */
78 bool dir_update_device(JCR *jcr, DEVICE *dev)
79 {
80    BSOCK *dir = jcr->dir_bsock;
81    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
82    DEVRES *device = dev->device;
83    bool ok;
84    
85    pm_strcpy(dev_name, device->hdr.name);
86    bash_spaces(dev_name);
87    if (dev->is_labeled()) {
88       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
89    } else {
90       pm_strcpy(VolumeName, "*");
91    }
92    bash_spaces(VolumeName);
93    pm_strcpy(MediaType, device->media_type);
94    bash_spaces(MediaType);
95    if (device->changer_res) {
96       pm_strcpy(ChangerName, device->changer_res->hdr.name);
97       bash_spaces(ChangerName);
98    } else {
99       pm_strcpy(ChangerName, "*");
100    }
101    ok = dir->fsend(Device_update, 
102       jcr->Job,
103       dev_name.c_str(),
104       dev->can_append()!=0,
105       dev->can_read()!=0, dev->num_writers, 
106       dev->is_open()!=0, dev->is_labeled()!=0,
107       dev->is_offline()!=0, dev->reserved_device, 
108       dev->is_tape()?100000:1,
109       dev->autoselect, 0, 
110       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
111    Dmsg1(100, ">dird: %s\n", dir->msg);
112    return ok;
113 }
114
115 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
116 {
117    BSOCK *dir = jcr->dir_bsock;
118    POOL_MEM dev_name, MediaType;
119    DEVRES *device;
120    bool ok;
121
122    pm_strcpy(dev_name, changer->hdr.name);
123    bash_spaces(dev_name);
124    device = (DEVRES *)changer->device->first();
125    pm_strcpy(MediaType, device->media_type);
126    bash_spaces(MediaType);
127    /* This is mostly to indicate that we are here */
128    ok = dir->fsend(Device_update,
129       jcr->Job,
130       dev_name.c_str(),         /* Changer name */
131       0, 0, 0,                  /* append, read, num_writers */
132       0, 0, 0,                  /* is_open, is_labeled, offline */
133       0, 0,                     /* reserved, max_writers */
134       0,                        /* Autoselect */
135       changer->device->size(),  /* Number of devices */
136       "0",                      /* PoolId */
137       "*",                      /* ChangerName */
138       MediaType.c_str(),        /* MediaType */
139       "*");                     /* VolName */
140    Dmsg1(100, ">dird: %s\n", dir->msg);
141    return ok;
142 }
143 #endif
144
145
146 /*
147  * Send current JobStatus to Director
148  */
149 bool dir_send_job_status(JCR *jcr)
150 {
151    return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus);
152 }
153
154 /*
155  * Common routine for:
156  *   dir_get_volume_info()
157  * and
158  *   dir_find_next_appendable_volume()
159  *
160  *  NOTE!!! All calls to this routine must be protected by
161  *          locking vol_info_mutex before calling it so that
162  *          we don't have one thread modifying the parameters
163  *          and another reading them.
164  *
165  *  Returns: true  on success and vol info in dcr->VolCatInfo
166  *           false on failure
167  */
168 static bool do_get_volume_info(DCR *dcr)
169 {
170     JCR *jcr = dcr->jcr;
171     BSOCK *dir = jcr->dir_bsock;
172     VOLUME_CAT_INFO vol;
173     int n;
174     int32_t InChanger;
175
176     if (dir->recv() <= 0) {
177        Dmsg0(200, "getvolname error bnet_recv\n");
178        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
179        return false;
180     }
181     memset(&vol, 0, sizeof(vol));
182     Dmsg1(100, "<dird %s", dir->msg);
183     n = sscanf(dir->msg, OK_media, vol.VolCatName,
184                &vol.VolCatJobs, &vol.VolCatFiles,
185                &vol.VolCatBlocks, &vol.VolCatBytes,
186                &vol.VolCatMounts, &vol.VolCatErrors,
187                &vol.VolCatWrites, &vol.VolCatMaxBytes,
188                &vol.VolCatCapacityBytes, vol.VolCatStatus,
189                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
190                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
191                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
192                &vol.LabelType, &vol.VolMediaId);
193     if (n != 22) {
194        Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
195              n, dir->msglen, dir->msg);
196        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
197        return false;
198     }
199     vol.InChanger = InChanger;        /* bool in structure */
200     unbash_spaces(vol.VolCatName);
201     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
202     dcr->VolCatInfo = vol;            /* structure assignment */
203
204     Dmsg2(100, "do_reqest_vol_info return true slot=%d Volume=%s\n",
205           vol.Slot, vol.VolCatName);
206     return true;
207 }
208
209
210 /*
211  * Get Volume info for a specific volume from the Director's Database
212  *
213  * Returns: true  on success   (Director guarantees that Pool and MediaType
214  *                              are correct and VolStatus==Append or
215  *                              VolStatus==Recycle)
216  *          false on failure
217  *
218  *          Volume information returned in dcr->VolCatInfo
219  */
220 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
221 {
222     JCR *jcr = dcr->jcr;
223     BSOCK *dir = jcr->dir_bsock;
224
225     P(vol_info_mutex);
226     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
227     bash_spaces(dcr->VolCatInfo.VolCatName);
228     dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
229        writing==GET_VOL_INFO_FOR_WRITE?1:0);
230     Dmsg1(100, ">dird %s", dir->msg);
231     unbash_spaces(dcr->VolCatInfo.VolCatName);
232     bool ok = do_get_volume_info(dcr);
233     V(vol_info_mutex);
234     return ok;
235 }
236
237
238
239 /*
240  * Get info on the next appendable volume in the Director's database
241  *
242  * Returns: true  on success dcr->VolumeName is volume
243  *                reserve_volume() called on Volume name
244  *          false on failure dcr->VolumeName[0] == 0
245  *                also sets dcr->volume_in_use if at least one 
246  *                in use volume was found.
247  *
248  *          Volume information returned in dcr
249  *
250  */
251 bool dir_find_next_appendable_volume(DCR *dcr)
252 {
253     JCR *jcr = dcr->jcr;
254     BSOCK *dir = jcr->dir_bsock;
255     bool found = false;
256
257     Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
258        dcr->reserved_device, dcr->VolumeName);
259
260     /*
261      * Try the twenty oldest or most available volumes.  Note,
262      *   the most available could already be mounted on another
263      *   drive, so we continue looking for a not in use Volume.
264      */
265     lock_reservations();
266     P(vol_info_mutex);
267     dcr->volume_in_use = false;
268     for (int vol_index=1;  vol_index < 20; vol_index++) {
269        bash_spaces(dcr->media_type);
270        bash_spaces(dcr->pool_name);
271        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
272        unbash_spaces(dcr->media_type);
273        unbash_spaces(dcr->pool_name);
274        Dmsg1(100, ">dird %s", dir->msg);
275        bool ok = do_get_volume_info(dcr);
276        if (ok) {
277           if (!is_volume_in_use(dcr)) {
278              found = true;
279              break;
280           } else {
281              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
282              dcr->volume_in_use = true;
283              continue;
284           }
285        } else {
286           Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
287              dcr->dev->print_name());
288           found = false;
289           break;
290        }
291     }
292     if (found) {
293        Dmsg0(400, "dir_find_next_appendable_volume return true\n");
294        if (reserve_volume(dcr, dcr->VolumeName) == 0) {
295           Dmsg2(100, "Could not reserve volume %s on %s\n", dcr->VolumeName,
296               dcr->dev->print_name());
297           goto bail_out;
298        }
299        V(vol_info_mutex);
300        unlock_reservations();
301        return true;
302     }
303
304 bail_out:
305     dcr->VolumeName[0] = 0;
306     V(vol_info_mutex);
307     unlock_reservations();
308     return false;
309 }
310
311
312 /*
313  * After writing a Volume, send the updated statistics
314  * back to the director. The information comes from the
315  * dev record.
316  */
317 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
318 {
319    JCR *jcr = dcr->jcr;
320    BSOCK *dir = jcr->dir_bsock;
321    DEVICE *dev = dcr->dev;
322    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
323    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
324    int InChanger;
325    bool ok = false;
326    POOL_MEM VolumeName;
327
328    /* If system job, do not update catalog */
329    if (jcr->JobType == JT_SYSTEM) {
330       return true;
331    }
332
333    if (vol->VolCatName[0] == 0) {
334       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
335       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
336       return false;
337    }
338
339    /* Lock during Volume update */
340    P(vol_info_mutex);
341    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
342    /* Just labeled or relabeled the tape */
343    if (label) {
344       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
345    }
346 // if (update_LastWritten) {
347       vol->VolLastWritten = time(NULL);
348 // }
349    pm_strcpy(VolumeName, vol->VolCatName);
350    bash_spaces(VolumeName);
351    InChanger = vol->InChanger;
352    dir->fsend(Update_media, jcr->Job,
353       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
354       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
355       vol->VolCatMounts, vol->VolCatErrors,
356       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
357       edit_uint64(vol->VolLastWritten, ed6), 
358       vol->VolCatStatus, vol->Slot, label,
359       InChanger,                      /* bool in structure */
360       edit_int64(vol->VolReadTime, ed3),
361       edit_int64(vol->VolWriteTime, ed4),
362       edit_uint64(vol->VolFirstWritten, ed5),
363       vol->VolCatParts);
364     Dmsg1(100, ">dird %s", dir->msg);
365
366    /* Do not lock device here because it may be locked from label */
367    if (!do_get_volume_info(dcr)) {
368       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
369       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
370          vol->VolCatName, jcr->errmsg);
371       goto bail_out;
372    }
373    Dmsg1(420, "get_volume_info() %s", dir->msg);
374    /* Update dev Volume info in case something changed (e.g. expired) */
375    dev->VolCatInfo = dcr->VolCatInfo;
376    ok = true;
377
378 bail_out:
379    V(vol_info_mutex);
380    return ok;
381 }
382
383 /*
384  * After writing a Volume, create the JobMedia record.
385  */
386 bool dir_create_jobmedia_record(DCR *dcr)
387 {
388    JCR *jcr = dcr->jcr;
389    BSOCK *dir = jcr->dir_bsock;
390    char ed1[50];
391
392    /* If system job, do not update catalog */
393    if (jcr->JobType == JT_SYSTEM) {
394       return true;
395    }
396
397    if (!dcr->WroteVol) {
398       return true;                    /* nothing written to tape */
399    }
400
401    dcr->WroteVol = false;
402    dir->fsend(Create_job_media, jcr->Job,
403       dcr->VolFirstIndex, dcr->VolLastIndex,
404       dcr->StartFile, dcr->EndFile,
405       dcr->StartBlock, dcr->EndBlock, 
406       dcr->Copy, dcr->Stripe, 
407       edit_uint64(dcr->VolMediaId, ed1));
408     Dmsg1(100, ">dird %s", dir->msg);
409    if (bnet_recv(dir) <= 0) {
410       Dmsg0(190, "create_jobmedia error bnet_recv\n");
411       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
412            dir->bstrerror());
413       return false;
414    }
415    Dmsg1(100, "<dird %s", dir->msg);
416    if (strcmp(dir->msg, OK_create) != 0) {
417       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
418       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
419       return false;
420    }
421    return true;
422 }
423
424
425 /*
426  * Update File Attribute data
427  */
428 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
429 {
430    JCR *jcr = dcr->jcr;
431    BSOCK *dir = jcr->dir_bsock;
432    ser_declare;
433
434 #ifdef NO_ATTRIBUTES_TEST
435    return true;
436 #endif
437
438    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
439                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
440    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
441                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
442    ser_begin(dir->msg + dir->msglen, 0);
443    ser_uint32(rec->VolSessionId);
444    ser_uint32(rec->VolSessionTime);
445    ser_int32(rec->FileIndex);
446    ser_int32(rec->Stream);
447    ser_uint32(rec->data_len);
448    ser_bytes(rec->data, rec->data_len);
449    dir->msglen = ser_length(dir->msg);
450    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
451    return dir->send();
452 }
453
454
455 /*
456  *   Request the sysop to create an appendable volume
457  *
458  *   Entered with device blocked.
459  *   Leaves with device blocked.
460  *
461  *   Returns: true  on success (operator issues a mount command)
462  *            false on failure
463  *              Note, must create dev->errmsg on error return.
464  *
465  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
466  *      information on suggested volume, but this may not be the
467  *      same as what is actually mounted.
468  *
469  *    When we return with success, the correct tape may or may not
470  *      actually be mounted. The calling routine must read it and
471  *      verify the label.
472  */
473 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
474 {
475    int stat = W_TIMEOUT;
476    DEVICE *dev = dcr->dev;
477    JCR *jcr = dcr->jcr;
478    bool got_vol = false;
479
480    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
481    ASSERT(dev->blocked());
482    for ( ;; ) {
483       if (job_canceled(jcr)) {
484          Mmsg(dev->errmsg,
485               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
486               jcr->Job, dev->print_name());
487          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
488          return false;
489       }
490       dev->dlock();  
491       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
492       dev->dunlock();
493       if (got_vol) {
494          return true;
495       } else {
496          if (stat == W_TIMEOUT || stat == W_MOUNT) {
497             Jmsg(jcr, M_MOUNT, 0, _(
498 "Job %s waiting. Cannot find any appendable volumes.\n"
499 "Please use the \"label\"  command to create a new Volume for:\n"
500 "    Storage:      %s\n"
501 "    Pool:         %s\n"
502 "    Media type:   %s\n"),
503                jcr->Job,
504                dev->print_name(),
505                dcr->pool_name,
506                dcr->media_type);
507          }
508       }
509
510       set_jcr_job_status(jcr, JS_WaitMedia);
511       dir_send_job_status(jcr);
512
513       stat = wait_for_sysop(dcr);
514       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
515       if (dev->poll) {
516          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
517          continue;
518       }
519
520       if (stat == W_TIMEOUT) {
521          if (!double_dev_wait_time(dev)) {
522             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
523                dev->print_name(), jcr->Job);
524             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
525             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
526             return false;             /* exceeded maximum waits */
527          }
528          continue;
529       }
530       if (stat == W_ERROR) {
531          berrno be;
532          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
533          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
534          return false;
535       }
536       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
537    }
538    set_jcr_job_status(jcr, JS_Running);
539    dir_send_job_status(jcr);
540    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
541    return true;
542 }
543
544 /*
545  *   Request to mount specific Volume
546  *
547  *   Entered with device blocked and dcr->VolumeName is desired
548  *      volume.
549  *   Leaves with device blocked.
550  *
551  *   Returns: true  on success (operator issues a mount command)
552  *            false on failure
553  *                  Note, must create dev->errmsg on error return.
554  *
555  */
556 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
557 {
558    int stat = W_TIMEOUT;
559    DEVICE *dev = dcr->dev;
560    JCR *jcr = dcr->jcr;
561
562    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
563    if (!dcr->VolumeName[0]) {
564       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
565       return false;
566    }
567    ASSERT(dev->blocked());
568    for ( ;; ) {
569       if (job_canceled(jcr)) {
570          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
571               jcr->Job, dev->print_name());
572          return false;
573       }
574
575       if (dev->is_dvd()) {   
576          dev->unmount(0);
577       }
578       
579       /*
580        * If we are not polling, and the wait timeout or the
581        *   user explicitly did a mount, send him the message.
582        *   Otherwise skip it.
583        */
584       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
585          Jmsg(jcr, M_MOUNT, 0, _("Please mount Volume \"%s\" or label a new one for:\n"
586               "    Job:          %s\n"
587               "    Storage:      %s\n"
588               "    Pool:         %s\n"
589               "    Media type:   %s\n"),
590               dcr->VolumeName,
591               jcr->Job,
592               dev->print_name(),
593               dcr->pool_name,
594               dcr->media_type);
595          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
596                dcr->VolumeName, dev->print_name(), jcr->Job);
597       }
598
599       set_jcr_job_status(jcr, JS_WaitMount);
600       dir_send_job_status(jcr);
601
602       stat = wait_for_sysop(dcr);          /* wait on device */
603       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
604       if (dev->poll) {
605          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
606          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
607          goto bail_out;
608       }
609
610       if (stat == W_TIMEOUT) {
611          if (!double_dev_wait_time(dev)) {
612             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
613                dev->print_name(), jcr->Job);
614             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
615             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
616             return false;             /* exceeded maximum waits */
617          }
618          continue;
619       }
620       if (stat == W_ERROR) {
621          berrno be;
622          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
623          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
624          return false;
625       }
626       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
627       break;
628    }
629
630 bail_out:
631    set_jcr_job_status(jcr, JS_Running);
632    dir_send_job_status(jcr);
633    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
634    return true;
635 }