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