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