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