]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
ebl Fix a volume update error.
[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=%s VolWriteTime=%s 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     char ed_vrt[50], ed_vwt[50];
171     JCR *jcr = dcr->jcr;
172     BSOCK *dir = jcr->dir_bsock;
173     VOLUME_CAT_INFO vol;
174     int n;
175     int32_t InChanger;
176
177     if (dir->recv() <= 0) {
178        Dmsg0(200, "getvolname error bnet_recv\n");
179        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
180        return false;
181     }
182     memset(&vol, 0, sizeof(vol));
183     Dmsg1(100, "<dird %s", dir->msg);
184     n = sscanf(dir->msg, OK_media, vol.VolCatName,
185                &vol.VolCatJobs, &vol.VolCatFiles,
186                &vol.VolCatBlocks, &vol.VolCatBytes,
187                &vol.VolCatMounts, &vol.VolCatErrors,
188                &vol.VolCatWrites, &vol.VolCatMaxBytes,
189                &vol.VolCatCapacityBytes, vol.VolCatStatus,
190                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
191                &InChanger, ed_vrt, ed_vwt,
192                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
193                &vol.LabelType, &vol.VolMediaId);
194     if (n != 22) {
195        Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
196              n, dir->msglen, dir->msg);
197        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
198        return false;
199     }
200     vol.VolReadTime = str_to_int64(ed_vrt);
201     vol.VolWriteTime = str_to_int64(ed_vwt);
202     vol.InChanger = InChanger;        /* bool in structure */
203     unbash_spaces(vol.VolCatName);
204     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
205     dcr->VolCatInfo = vol;            /* structure assignment */
206
207     Dmsg2(100, "do_reqest_vol_info return true slot=%d Volume=%s\n",
208           vol.Slot, vol.VolCatName);
209     return true;
210 }
211
212
213 /*
214  * Get Volume info for a specific volume from the Director's Database
215  *
216  * Returns: true  on success   (Director guarantees that Pool and MediaType
217  *                              are correct and VolStatus==Append or
218  *                              VolStatus==Recycle)
219  *          false on failure
220  *
221  *          Volume information returned in dcr->VolCatInfo
222  */
223 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
224 {
225     JCR *jcr = dcr->jcr;
226     BSOCK *dir = jcr->dir_bsock;
227
228     P(vol_info_mutex);
229     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
230     bash_spaces(dcr->VolCatInfo.VolCatName);
231     dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
232        writing==GET_VOL_INFO_FOR_WRITE?1:0);
233     Dmsg1(100, ">dird %s", dir->msg);
234     unbash_spaces(dcr->VolCatInfo.VolCatName);
235     bool ok = do_get_volume_info(dcr);
236     V(vol_info_mutex);
237     return ok;
238 }
239
240
241
242 /*
243  * Get info on the next appendable volume in the Director's database
244  *
245  * Returns: true  on success dcr->VolumeName is volume
246  *                reserve_volume() called on Volume name
247  *          false on failure dcr->VolumeName[0] == 0
248  *                also sets dcr->volume_in_use if at least one 
249  *                in use volume was found.
250  *
251  *          Volume information returned in dcr
252  *
253  */
254 bool dir_find_next_appendable_volume(DCR *dcr)
255 {
256     JCR *jcr = dcr->jcr;
257     BSOCK *dir = jcr->dir_bsock;
258     bool rtn;
259
260     Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
261        dcr->reserved_device, dcr->VolumeName);
262
263     /*
264      * Try the fourty oldest or most available volumes.  Note,
265      *   the most available could already be mounted on another
266      *   drive, so we continue looking for a not in use Volume.
267      */
268     lock_volumes();
269     P(vol_info_mutex);
270     dcr->volume_in_use = false;
271     for (int vol_index=1;  vol_index < 40; vol_index++) {
272        bash_spaces(dcr->media_type);
273        bash_spaces(dcr->pool_name);
274        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
275        unbash_spaces(dcr->media_type);
276        unbash_spaces(dcr->pool_name);
277        Dmsg1(100, ">dird %s", dir->msg);
278        if (do_get_volume_info(dcr)) {
279           if (!is_volume_in_use(dcr)) {
280              Dmsg1(100, "Call reserve_volume. Vol=%s\n", dcr->VolumeName);
281              if (reserve_volume(dcr, dcr->VolumeName) == 0) {
282                 Dmsg2(100, "Could not reserve volume %s on %s\n", dcr->VolumeName,
283                     dcr->dev->print_name());
284                 continue;
285              }
286              Dmsg1(100, "dir_find_next_appendable_volume return true. vol=%s\n",
287                 dcr->VolumeName);
288              rtn = true;
289              goto get_out;
290           } else {
291              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
292              dcr->volume_in_use = true;
293              continue;
294           }
295        }
296        Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
297           dcr->dev->print_name());
298        break;
299     }
300     rtn = false;
301     dcr->VolumeName[0] = 0;
302
303 get_out:
304     V(vol_info_mutex);
305     unlock_volumes();
306     return rtn;
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, bool update_LastWritten)
316 {
317    JCR *jcr = dcr->jcr;
318    BSOCK *dir = jcr->dir_bsock;
319    DEVICE *dev = dcr->dev;
320    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
321    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
322    int InChanger;
323    bool ok = false;
324    POOL_MEM VolumeName;
325
326    /* If system job, do not update catalog */
327    if (jcr->JobType == JT_SYSTEM) {
328       return true;
329    }
330
331    if (vol->VolCatName[0] == 0) {
332       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
333       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
334       return false;
335    }
336
337    /* Lock during Volume update */
338    P(vol_info_mutex);
339    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
340    /* Just labeled or relabeled the tape */
341    if (label) {
342       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
343    }
344 // if (update_LastWritten) {
345       vol->VolLastWritten = time(NULL);
346 // }
347    pm_strcpy(VolumeName, vol->VolCatName);
348    bash_spaces(VolumeName);
349    InChanger = vol->InChanger;
350    dir->fsend(Update_media, jcr->Job,
351       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
352       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
353       vol->VolCatMounts, vol->VolCatErrors,
354       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
355       edit_uint64(vol->VolLastWritten, ed6), 
356       vol->VolCatStatus, vol->Slot, label,
357       InChanger,                      /* bool in structure */
358       edit_int64(vol->VolReadTime, ed3),
359       edit_int64(vol->VolWriteTime, ed4),
360       edit_uint64(vol->VolFirstWritten, ed5),
361       vol->VolCatParts);
362     Dmsg1(100, ">dird %s", dir->msg);
363
364    /* Do not lock device here because it may be locked from label */
365    if (!do_get_volume_info(dcr)) {
366       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
367       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
368          vol->VolCatName, jcr->errmsg);
369       goto bail_out;
370    }
371    Dmsg1(420, "get_volume_info() %s", dir->msg);
372    /* Update dev Volume info in case something changed (e.g. expired) */
373    dev->VolCatInfo = dcr->VolCatInfo;
374    ok = true;
375
376 bail_out:
377    V(vol_info_mutex);
378    return ok;
379 }
380
381 /*
382  * After writing a Volume, create the JobMedia record.
383  */
384 bool dir_create_jobmedia_record(DCR *dcr)
385 {
386    JCR *jcr = dcr->jcr;
387    BSOCK *dir = jcr->dir_bsock;
388    char ed1[50];
389
390    /* If system job, do not update catalog */
391    if (jcr->JobType == JT_SYSTEM) {
392       return true;
393    }
394
395    if (!dcr->WroteVol) {
396       return true;                    /* nothing written to tape */
397    }
398
399    dcr->WroteVol = false;
400    dir->fsend(Create_job_media, jcr->Job,
401       dcr->VolFirstIndex, dcr->VolLastIndex,
402       dcr->StartFile, dcr->EndFile,
403       dcr->StartBlock, dcr->EndBlock, 
404       dcr->Copy, dcr->Stripe, 
405       edit_uint64(dcr->VolMediaId, ed1));
406     Dmsg1(100, ">dird %s", dir->msg);
407    if (dir->recv() <= 0) {
408       Dmsg0(190, "create_jobmedia error bnet_recv\n");
409       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
410            dir->bstrerror());
411       return false;
412    }
413    Dmsg1(100, "<dird %s", dir->msg);
414    if (strcmp(dir->msg, OK_create) != 0) {
415       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
416       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
417       return false;
418    }
419    return true;
420 }
421
422
423 /*
424  * Update File Attribute data
425  */
426 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
427 {
428    JCR *jcr = dcr->jcr;
429    BSOCK *dir = jcr->dir_bsock;
430    ser_declare;
431
432 #ifdef NO_ATTRIBUTES_TEST
433    return true;
434 #endif
435
436    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
437                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
438    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
439                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
440    ser_begin(dir->msg + dir->msglen, 0);
441    ser_uint32(rec->VolSessionId);
442    ser_uint32(rec->VolSessionTime);
443    ser_int32(rec->FileIndex);
444    ser_int32(rec->Stream);
445    ser_uint32(rec->data_len);
446    ser_bytes(rec->data, rec->data_len);
447    dir->msglen = ser_length(dir->msg);
448    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
449    return dir->send();
450 }
451
452
453 /*
454  *   Request the sysop to create an appendable volume
455  *
456  *   Entered with device blocked.
457  *   Leaves with device blocked.
458  *
459  *   Returns: true  on success (operator issues a mount command)
460  *            false on failure
461  *              Note, must create dev->errmsg on error return.
462  *
463  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
464  *      information on suggested volume, but this may not be the
465  *      same as what is actually mounted.
466  *
467  *    When we return with success, the correct tape may or may not
468  *      actually be mounted. The calling routine must read it and
469  *      verify the label.
470  */
471 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
472 {
473    int stat = W_TIMEOUT;
474    DEVICE *dev = dcr->dev;
475    JCR *jcr = dcr->jcr;
476    bool got_vol = false;
477
478    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
479    ASSERT(dev->blocked());
480    for ( ;; ) {
481       if (job_canceled(jcr)) {
482          Mmsg(dev->errmsg,
483               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
484               jcr->Job, dev->print_name());
485          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
486          return false;
487       }
488       dev->dlock();  
489       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
490       dev->dunlock();
491       if (got_vol) {
492          return true;
493       } else {
494          if (stat == W_TIMEOUT || stat == W_MOUNT) {
495             Jmsg(jcr, M_MOUNT, 0, _(
496 "Job %s waiting. Cannot find any appendable volumes.\n"
497 "Please use the \"label\"  command to create a new Volume for:\n"
498 "    Storage:      %s\n"
499 "    Pool:         %s\n"
500 "    Media type:   %s\n"),
501                jcr->Job,
502                dev->print_name(),
503                dcr->pool_name,
504                dcr->media_type);
505          }
506       }
507
508       set_jcr_job_status(jcr, JS_WaitMedia);
509       dir_send_job_status(jcr);
510
511       stat = wait_for_sysop(dcr);
512       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
513       if (dev->poll) {
514          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
515          continue;
516       }
517
518       if (stat == W_TIMEOUT) {
519          if (!double_dev_wait_time(dev)) {
520             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
521                dev->print_name(), jcr->Job);
522             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
523             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
524             return false;             /* exceeded maximum waits */
525          }
526          continue;
527       }
528       if (stat == W_ERROR) {
529          berrno be;
530          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
531          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
532          return false;
533       }
534       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
535    }
536    set_jcr_job_status(jcr, JS_Running);
537    dir_send_job_status(jcr);
538    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
539    return true;
540 }
541
542 /*
543  *   Request to mount specific Volume
544  *
545  *   Entered with device blocked and dcr->VolumeName is desired
546  *      volume.
547  *   Leaves with device blocked.
548  *
549  *   Returns: true  on success (operator issues a mount command)
550  *            false on failure
551  *                  Note, must create dev->errmsg on error return.
552  *
553  */
554 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode)
555 {
556    int stat = W_TIMEOUT;
557    DEVICE *dev = dcr->dev;
558    JCR *jcr = dcr->jcr;
559
560    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
561    if (!dcr->VolumeName[0]) {
562       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
563       return false;
564    }
565    ASSERT(dev->blocked());
566    for ( ;; ) {
567       if (job_canceled(jcr)) {
568          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
569               jcr->Job, dev->print_name());
570          return false;
571       }
572
573       if (dev->is_dvd()) {   
574          dev->unmount(0);
575       }
576       
577       /*
578        * If we are not polling, and the wait timeout or the
579        *   user explicitly did a mount, send him the message.
580        *   Otherwise skip it.
581        */
582       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
583          char *msg;
584          if (mode == ST_APPEND) {
585             msg = _("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          } else {
591             msg = _("Please mount Volume \"%s\" for:\n"
592               "    Job:          %s\n"
593               "    Storage:      %s\n"
594               "    Pool:         %s\n"
595               "    Media type:   %s\n");
596          }
597          Jmsg(jcr, M_MOUNT, 0, msg, 
598               dcr->VolumeName,
599               jcr->Job,
600               dev->print_name(),
601               dcr->pool_name,
602               dcr->media_type);
603          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
604                dcr->VolumeName, dev->print_name(), jcr->Job);
605       }
606
607       set_jcr_job_status(jcr, JS_WaitMount);
608       dir_send_job_status(jcr);
609
610       stat = wait_for_sysop(dcr);          /* wait on device */
611       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
612       if (dev->poll) {
613          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
614          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
615          goto bail_out;
616       }
617
618       if (stat == W_TIMEOUT) {
619          if (!double_dev_wait_time(dev)) {
620             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
621                dev->print_name(), jcr->Job);
622             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
623             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
624             return false;             /* exceeded maximum waits */
625          }
626          continue;
627       }
628       if (stat == W_ERROR) {
629          berrno be;
630          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
631          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
632          return false;
633       }
634       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
635       break;
636    }
637
638 bail_out:
639    set_jcr_job_status(jcr, JS_Running);
640    dir_send_job_status(jcr);
641    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
642    return true;
643 }