]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Tweak debug + code indenting
[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              Dmsg1(100, "Attempt reserve. 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              V(vol_info_mutex);
284              unlock_reservations();
285              Dmsg1(100, "dir_find_next_appendable_volume return true. vol=%s\n",
286                 dcr->VolumeName);
287              return true;
288           } else {
289              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
290              dcr->volume_in_use = true;
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
299     dcr->VolumeName[0] = 0;
300     V(vol_info_mutex);
301     unlock_reservations();
302     return false;
303 }
304
305
306 /*
307  * After writing a Volume, send the updated statistics
308  * back to the director. The information comes from the
309  * dev record.
310  */
311 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
312 {
313    JCR *jcr = dcr->jcr;
314    BSOCK *dir = jcr->dir_bsock;
315    DEVICE *dev = dcr->dev;
316    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
317    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
318    int InChanger;
319    bool ok = false;
320    POOL_MEM VolumeName;
321
322    /* If system job, do not update catalog */
323    if (jcr->JobType == JT_SYSTEM) {
324       return true;
325    }
326
327    if (vol->VolCatName[0] == 0) {
328       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
329       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
330       return false;
331    }
332
333    /* Lock during Volume update */
334    P(vol_info_mutex);
335    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
336    /* Just labeled or relabeled the tape */
337    if (label) {
338       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
339    }
340 // if (update_LastWritten) {
341       vol->VolLastWritten = time(NULL);
342 // }
343    pm_strcpy(VolumeName, vol->VolCatName);
344    bash_spaces(VolumeName);
345    InChanger = vol->InChanger;
346    dir->fsend(Update_media, jcr->Job,
347       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
348       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
349       vol->VolCatMounts, vol->VolCatErrors,
350       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
351       edit_uint64(vol->VolLastWritten, ed6), 
352       vol->VolCatStatus, vol->Slot, label,
353       InChanger,                      /* bool in structure */
354       edit_int64(vol->VolReadTime, ed3),
355       edit_int64(vol->VolWriteTime, ed4),
356       edit_uint64(vol->VolFirstWritten, ed5),
357       vol->VolCatParts);
358     Dmsg1(100, ">dird %s", dir->msg);
359
360    /* Do not lock device here because it may be locked from label */
361    if (!do_get_volume_info(dcr)) {
362       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
363       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
364          vol->VolCatName, jcr->errmsg);
365       goto bail_out;
366    }
367    Dmsg1(420, "get_volume_info() %s", dir->msg);
368    /* Update dev Volume info in case something changed (e.g. expired) */
369    dev->VolCatInfo = dcr->VolCatInfo;
370    ok = true;
371
372 bail_out:
373    V(vol_info_mutex);
374    return ok;
375 }
376
377 /*
378  * After writing a Volume, create the JobMedia record.
379  */
380 bool dir_create_jobmedia_record(DCR *dcr)
381 {
382    JCR *jcr = dcr->jcr;
383    BSOCK *dir = jcr->dir_bsock;
384    char ed1[50];
385
386    /* If system job, do not update catalog */
387    if (jcr->JobType == JT_SYSTEM) {
388       return true;
389    }
390
391    if (!dcr->WroteVol) {
392       return true;                    /* nothing written to tape */
393    }
394
395    dcr->WroteVol = false;
396    dir->fsend(Create_job_media, jcr->Job,
397       dcr->VolFirstIndex, dcr->VolLastIndex,
398       dcr->StartFile, dcr->EndFile,
399       dcr->StartBlock, dcr->EndBlock, 
400       dcr->Copy, dcr->Stripe, 
401       edit_uint64(dcr->VolMediaId, ed1));
402     Dmsg1(100, ">dird %s", dir->msg);
403    if (bnet_recv(dir) <= 0) {
404       Dmsg0(190, "create_jobmedia error bnet_recv\n");
405       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
406            dir->bstrerror());
407       return false;
408    }
409    Dmsg1(100, "<dird %s", dir->msg);
410    if (strcmp(dir->msg, OK_create) != 0) {
411       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
412       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
413       return false;
414    }
415    return true;
416 }
417
418
419 /*
420  * Update File Attribute data
421  */
422 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
423 {
424    JCR *jcr = dcr->jcr;
425    BSOCK *dir = jcr->dir_bsock;
426    ser_declare;
427
428 #ifdef NO_ATTRIBUTES_TEST
429    return true;
430 #endif
431
432    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
433                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
434    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
435                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
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    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
445    return dir->send();
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, int mode)
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          char *msg;
580          if (mode == ST_APPEND) {
581             msg = _("Please mount Volume \"%s\" or label a new one for:\n"
582               "    Job:          %s\n"
583               "    Storage:      %s\n"
584               "    Pool:         %s\n"
585               "    Media type:   %s\n");
586          } else {
587             msg = _("Please mount Volume \"%s\" for:\n"
588               "    Job:          %s\n"
589               "    Storage:      %s\n"
590               "    Pool:         %s\n"
591               "    Media type:   %s\n");
592          }
593          Jmsg(jcr, M_MOUNT, 0, msg, 
594               dcr->VolumeName,
595               jcr->Job,
596               dev->print_name(),
597               dcr->pool_name,
598               dcr->media_type);
599          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
600                dcr->VolumeName, dev->print_name(), jcr->Job);
601       }
602
603       set_jcr_job_status(jcr, JS_WaitMount);
604       dir_send_job_status(jcr);
605
606       stat = wait_for_sysop(dcr);          /* wait on device */
607       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
608       if (dev->poll) {
609          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
610          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
611          goto bail_out;
612       }
613
614       if (stat == W_TIMEOUT) {
615          if (!double_dev_wait_time(dev)) {
616             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
617                dev->print_name(), jcr->Job);
618             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
619             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
620             return false;             /* exceeded maximum waits */
621          }
622          continue;
623       }
624       if (stat == W_ERROR) {
625          berrno be;
626          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
627          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
628          return false;
629       }
630       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
631       break;
632    }
633
634 bail_out:
635    set_jcr_job_status(jcr, JS_Running);
636    dir_send_job_status(jcr);
637    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
638    return true;
639 }