]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
kes Rework class structures for VOLRES, DCR, and DEVICE to make
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 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->found_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 rtn;
256
257     Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
258        dcr->is_reserved(), dcr->VolumeName);
259
260     /*
261      * Try the forty 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_volumes();
266     P(vol_info_mutex);
267     dcr->clear_found_in_use();
268     for (int vol_index=1;  vol_index < 40; 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        if (do_get_volume_info(dcr)) {
276           if (dcr->can_i_use_volume()) {
277              Dmsg1(100, "Call reserve_volume. Vol=%s\n", dcr->VolumeName);
278              if (reserve_volume(dcr, dcr->VolumeName) == 0) {
279                 Dmsg2(100, "Could not reserve volume %s on %s\n", dcr->VolumeName,
280                     dcr->dev->print_name());
281                 continue;
282              }
283              Dmsg1(100, "dir_find_next_appendable_volume return true. vol=%s\n",
284                 dcr->VolumeName);
285              rtn = true;
286              goto get_out;
287           } else {
288              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
289              /* If volume is not usable, it is in use by someone else */
290              dcr->set_found_in_use();
291              continue;
292           }
293        }
294        Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
295           dcr->dev->print_name());
296        break;
297     }
298     rtn = false;
299     dcr->VolumeName[0] = 0;
300
301 get_out:
302     V(vol_info_mutex);
303     unlock_volumes();
304     return rtn;
305 }
306
307
308 /*
309  * After writing a Volume, send the updated statistics
310  * back to the director. The information comes from the
311  * dev record.
312  */
313 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
314 {
315    JCR *jcr = dcr->jcr;
316    BSOCK *dir = jcr->dir_bsock;
317    DEVICE *dev = dcr->dev;
318    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
319    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
320    int InChanger;
321    bool ok = false;
322    POOL_MEM VolumeName;
323
324    /* If system job, do not update catalog */
325    if (jcr->JobType == JT_SYSTEM) {
326       return true;
327    }
328
329    if (vol->VolCatName[0] == 0) {
330       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
331       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
332       return false;
333    }
334
335    /* Lock during Volume update */
336    P(vol_info_mutex);
337    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
338    /* Just labeled or relabeled the tape */
339    if (label) {
340       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
341    }
342 // if (update_LastWritten) {
343       vol->VolLastWritten = time(NULL);
344 // }
345    pm_strcpy(VolumeName, vol->VolCatName);
346    bash_spaces(VolumeName);
347    InChanger = vol->InChanger;
348    dir->fsend(Update_media, jcr->Job,
349       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
350       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
351       vol->VolCatMounts, vol->VolCatErrors,
352       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
353       edit_uint64(vol->VolLastWritten, ed6), 
354       vol->VolCatStatus, vol->Slot, label,
355       InChanger,                      /* bool in structure */
356       edit_int64(vol->VolReadTime, ed3),
357       edit_int64(vol->VolWriteTime, ed4),
358       edit_uint64(vol->VolFirstWritten, ed5),
359       vol->VolCatParts);
360     Dmsg1(100, ">dird %s", dir->msg);
361
362    /* Do not lock device here because it may be locked from label */
363    if (!do_get_volume_info(dcr)) {
364       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
365       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
366          vol->VolCatName, jcr->errmsg);
367       goto bail_out;
368    }
369    Dmsg1(420, "get_volume_info() %s", dir->msg);
370    /* Update dev Volume info in case something changed (e.g. expired) */
371    dev->VolCatInfo = dcr->VolCatInfo;
372    ok = true;
373
374 bail_out:
375    V(vol_info_mutex);
376    return ok;
377 }
378
379 /*
380  * After writing a Volume, create the JobMedia record.
381  */
382 bool dir_create_jobmedia_record(DCR *dcr)
383 {
384    JCR *jcr = dcr->jcr;
385    BSOCK *dir = jcr->dir_bsock;
386    char ed1[50];
387
388    /* If system job, do not update catalog */
389    if (jcr->JobType == JT_SYSTEM) {
390       return true;
391    }
392
393    if (!dcr->WroteVol) {
394       return true;                    /* nothing written to tape */
395    }
396
397    dcr->WroteVol = false;
398    dir->fsend(Create_job_media, jcr->Job,
399       dcr->VolFirstIndex, dcr->VolLastIndex,
400       dcr->StartFile, dcr->EndFile,
401       dcr->StartBlock, dcr->EndBlock, 
402       dcr->Copy, dcr->Stripe, 
403       edit_uint64(dcr->VolMediaId, ed1));
404     Dmsg1(100, ">dird %s", dir->msg);
405    if (dir->recv() <= 0) {
406       Dmsg0(190, "create_jobmedia error bnet_recv\n");
407       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
408            dir->bstrerror());
409       return false;
410    }
411    Dmsg1(100, "<dird %s", dir->msg);
412    if (strcmp(dir->msg, OK_create) != 0) {
413       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
414       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
415       return false;
416    }
417    return true;
418 }
419
420
421 /*
422  * Update File Attribute data
423  */
424 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
425 {
426    JCR *jcr = dcr->jcr;
427    BSOCK *dir = jcr->dir_bsock;
428    ser_declare;
429
430 #ifdef NO_ATTRIBUTES_TEST
431    return true;
432 #endif
433
434    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
435                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
436    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
437                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
438    ser_begin(dir->msg + dir->msglen, 0);
439    ser_uint32(rec->VolSessionId);
440    ser_uint32(rec->VolSessionTime);
441    ser_int32(rec->FileIndex);
442    ser_int32(rec->Stream);
443    ser_uint32(rec->data_len);
444    ser_bytes(rec->data, rec->data_len);
445    dir->msglen = ser_length(dir->msg);
446    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
447    return dir->send();
448 }
449
450
451 /*
452  *   Request the sysop to create an appendable volume
453  *
454  *   Entered with device blocked.
455  *   Leaves with device blocked.
456  *
457  *   Returns: true  on success (operator issues a mount command)
458  *            false on failure
459  *              Note, must create dev->errmsg on error return.
460  *
461  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
462  *      information on suggested volume, but this may not be the
463  *      same as what is actually mounted.
464  *
465  *    When we return with success, the correct tape may or may not
466  *      actually be mounted. The calling routine must read it and
467  *      verify the label.
468  */
469 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
470 {
471    int stat = W_TIMEOUT;
472    DEVICE *dev = dcr->dev;
473    JCR *jcr = dcr->jcr;
474    bool got_vol = false;
475
476    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
477    ASSERT(dev->blocked());
478    for ( ;; ) {
479       if (job_canceled(jcr)) {
480          Mmsg(dev->errmsg,
481               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
482               jcr->Job, dev->print_name());
483          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
484          return false;
485       }
486       dev->dlock();  
487       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
488       dev->dunlock();
489       if (got_vol) {
490          return true;
491       } else {
492          if (stat == W_TIMEOUT || stat == W_MOUNT) {
493             Jmsg(jcr, M_MOUNT, 0, _(
494 "Job %s waiting. Cannot find any appendable volumes.\n"
495 "Please use the \"label\"  command to create a new Volume for:\n"
496 "    Storage:      %s\n"
497 "    Pool:         %s\n"
498 "    Media type:   %s\n"),
499                jcr->Job,
500                dev->print_name(),
501                dcr->pool_name,
502                dcr->media_type);
503          }
504       }
505
506       set_jcr_job_status(jcr, JS_WaitMedia);
507       dir_send_job_status(jcr);
508
509       stat = wait_for_sysop(dcr);
510       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
511       if (dev->poll) {
512          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
513          continue;
514       }
515
516       if (stat == W_TIMEOUT) {
517          if (!double_dev_wait_time(dev)) {
518             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
519                dev->print_name(), jcr->Job);
520             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
521             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
522             return false;             /* exceeded maximum waits */
523          }
524          continue;
525       }
526       if (stat == W_ERROR) {
527          berrno be;
528          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
529          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
530          return false;
531       }
532       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
533    }
534    set_jcr_job_status(jcr, JS_Running);
535    dir_send_job_status(jcr);
536    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
537    return true;
538 }
539
540 /*
541  *   Request to mount specific Volume
542  *
543  *   Entered with device blocked and dcr->VolumeName is desired
544  *      volume.
545  *   Leaves with device blocked.
546  *
547  *   Returns: true  on success (operator issues a mount command)
548  *            false on failure
549  *                  Note, must create dev->errmsg on error return.
550  *
551  */
552 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode)
553 {
554    int stat = W_TIMEOUT;
555    DEVICE *dev = dcr->dev;
556    JCR *jcr = dcr->jcr;
557
558    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
559    if (!dcr->VolumeName[0]) {
560       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
561       return false;
562    }
563    ASSERT(dev->blocked());
564    for ( ;; ) {
565       if (job_canceled(jcr)) {
566          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
567               jcr->Job, dev->print_name());
568          return false;
569       }
570
571       if (dev->is_dvd()) {   
572          dev->unmount(0);
573       }
574       
575       /*
576        * If we are not polling, and the wait timeout or the
577        *   user explicitly did a mount, send him the message.
578        *   Otherwise skip it.
579        */
580       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
581          char *msg;
582          if (mode == ST_APPEND) {
583             msg = _("Please mount Volume \"%s\" or label a new one for:\n"
584               "    Job:          %s\n"
585               "    Storage:      %s\n"
586               "    Pool:         %s\n"
587               "    Media type:   %s\n");
588          } else {
589             msg = _("Please mount Volume \"%s\" for:\n"
590               "    Job:          %s\n"
591               "    Storage:      %s\n"
592               "    Pool:         %s\n"
593               "    Media type:   %s\n");
594          }
595          Jmsg(jcr, M_MOUNT, 0, msg, 
596               dcr->VolumeName,
597               jcr->Job,
598               dev->print_name(),
599               dcr->pool_name,
600               dcr->media_type);
601          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
602                dcr->VolumeName, dev->print_name(), jcr->Job);
603       }
604
605       set_jcr_job_status(jcr, JS_WaitMount);
606       dir_send_job_status(jcr);
607
608       stat = wait_for_sysop(dcr);          /* wait on device */
609       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
610       if (dev->poll) {
611          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
612          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
613          goto bail_out;
614       }
615
616       if (stat == W_TIMEOUT) {
617          if (!double_dev_wait_time(dev)) {
618             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
619                dev->print_name(), jcr->Job);
620             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
621             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
622             return false;             /* exceeded maximum waits */
623          }
624          continue;
625       }
626       if (stat == W_ERROR) {
627          berrno be;
628          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
629          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
630          return false;
631       }
632       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
633       break;
634    }
635
636 bail_out:
637    set_jcr_job_status(jcr, JS_Running);
638    dir_send_job_status(jcr);
639    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
640    return true;
641 }