]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
a5ac547be5173003b24e20a417cca157f645ec84
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2012 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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  */
35
36 #include "bacula.h"                   /* pull in global headers */
37 #include "stored.h"                   /* pull in Storage Deamon headers */
38
39 /* Requests sent to the Director */
40 static char Find_media[]   = "CatReq Job=%s FindMedia=%d pool_name=%s media_type=%s\n";
41 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
42 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
43    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
44    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
45    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
46    " VolFirstWritten=%s VolParts=%u\n";
47 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
48    " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
49    " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%s\n";
50 static char FileAttributes[] = "UpdCat Job=%s FileAttributes ";
51
52 /* Responses received from the Director */
53 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
54    " VolBlocks=%lu VolBytes=%lld VolMounts=%lu VolErrors=%lu VolWrites=%lu"
55    " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s"
56    " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
57    " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
58    " VolParts=%lu LabelType=%ld MediaId=%lld\n";
59
60
61 static char OK_create[] = "1000 OK CreateJobMedia\n";
62
63 static pthread_mutex_t vol_info_mutex = PTHREAD_MUTEX_INITIALIZER;
64
65 #ifdef needed
66
67 static char Device_update[] = "DevUpd Job=%s device=%s "
68    "append=%d read=%d num_writers=%d "
69    "open=%d labeled=%d offline=%d "
70    "reserved=%d max_writers=%d "
71    "autoselect=%d autochanger=%d "
72    "changer_name=%s media_type=%s volume_name=%s\n";
73
74
75 /** Send update information about a device to Director */
76 bool dir_update_device(JCR *jcr, DEVICE *dev)
77 {
78    BSOCK *dir = jcr->dir_bsock;
79    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
80    DEVRES *device = dev->device;
81    bool ok;
82    
83    pm_strcpy(dev_name, device->hdr.name);
84    bash_spaces(dev_name);
85    if (dev->is_labeled()) {
86       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
87    } else {
88       pm_strcpy(VolumeName, "*");
89    }
90    bash_spaces(VolumeName);
91    pm_strcpy(MediaType, device->media_type);
92    bash_spaces(MediaType);
93    if (device->changer_res) {
94       pm_strcpy(ChangerName, device->changer_res->hdr.name);
95       bash_spaces(ChangerName);
96    } else {
97       pm_strcpy(ChangerName, "*");
98    }
99    ok = dir->fsend(Device_update, 
100       jcr->Job,
101       dev_name.c_str(),
102       dev->can_append()!=0,
103       dev->can_read()!=0, dev->num_writers, 
104       dev->is_open()!=0, dev->is_labeled()!=0,
105       dev->is_offline()!=0, dev->reserved_device, 
106       dev->is_tape()?100000:1,
107       dev->autoselect, 0, 
108       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
109    Dmsg1(100, ">dird: %s\n", dir->msg);
110    return ok;
111 }
112
113 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
114 {
115    BSOCK *dir = jcr->dir_bsock;
116    POOL_MEM dev_name, MediaType;
117    DEVRES *device;
118    bool ok;
119
120    pm_strcpy(dev_name, changer->hdr.name);
121    bash_spaces(dev_name);
122    device = (DEVRES *)changer->device->first();
123    pm_strcpy(MediaType, device->media_type);
124    bash_spaces(MediaType);
125    /* This is mostly to indicate that we are here */
126    ok = dir->fsend(Device_update,
127       jcr->Job,
128       dev_name.c_str(),         /* Changer name */
129       0, 0, 0,                  /* append, read, num_writers */
130       0, 0, 0,                  /* is_open, is_labeled, offline */
131       0, 0,                     /* reserved, max_writers */
132       0,                        /* Autoselect */
133       changer->device->size(),  /* Number of devices */
134       "0",                      /* PoolId */
135       "*",                      /* ChangerName */
136       MediaType.c_str(),        /* MediaType */
137       "*");                     /* VolName */
138    Dmsg1(100, ">dird: %s\n", dir->msg);
139    return ok;
140 }
141 #endif
142
143
144 /**
145  * Send current JobStatus to Director
146  */
147 bool dir_send_job_status(JCR *jcr)
148 {
149    return jcr->sendJobStatus();
150 }
151
152 /**
153  * Common routine for:
154  *   dir_get_volume_info()
155  * and
156  *   dir_find_next_appendable_volume()
157  *
158  *  NOTE!!! All calls to this routine must be protected by
159  *          locking vol_info_mutex before calling it so that
160  *          we don't have one thread modifying the parameters
161  *          and another reading them.
162  *
163  *  Returns: true  on success and vol info in dcr->VolCatInfo
164  *           false on failure
165  */
166 static bool do_get_volume_info(DCR *dcr)
167 {
168     JCR *jcr = dcr->jcr;
169     BSOCK *dir = jcr->dir_bsock;
170     VOLUME_CAT_INFO vol;
171     int n;
172     int32_t InChanger;
173
174     dcr->setVolCatInfo(false);
175     if (dir->recv() <= 0) {
176        Dmsg0(200, "getvolname error bnet_recv\n");
177        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
178        return false;
179     }
180     memset(&vol, 0, sizeof(vol));
181     Dmsg1(100, "<dird %s", dir->msg);
182     n = sscanf(dir->msg, OK_media, vol.VolCatName,
183                &vol.VolCatJobs, &vol.VolCatFiles,
184                &vol.VolCatBlocks, &vol.VolCatBytes,
185                &vol.VolCatMounts, &vol.VolCatErrors,
186                &vol.VolCatWrites, &vol.VolCatMaxBytes,
187                &vol.VolCatCapacityBytes, vol.VolCatStatus,
188                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
189                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
190                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
191                &vol.LabelType, &vol.VolMediaId);
192     if (n != 22) {
193        Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
194              n, dir->msglen, dir->msg);
195        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
196        return false;
197     }
198     vol.InChanger = InChanger;        /* bool in structure */
199     vol.is_valid = true;
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     dcr->setVolCatName(dcr->VolumeName);
227     bash_spaces(dcr->getVolCatName());
228     dir->fsend(Get_Vol_Info, jcr->Job, dcr->getVolCatName(),
229        writing==GET_VOL_INFO_FOR_WRITE?1:0);
230     Dmsg1(100, ">dird %s", dir->msg);
231     unbash_spaces(dcr->getVolCatName());
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->found_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 rtn;
256     char lastVolume[MAX_NAME_LENGTH];
257
258     Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
259        dcr->is_reserved(), dcr->VolumeName);
260
261     /*
262      * Try the twenty oldest or most available volumes.  Note,
263      *   the most available could already be mounted on another
264      *   drive, so we continue looking for a not in use Volume.
265      */
266     lock_volumes();
267     P(vol_info_mutex);
268     dcr->clear_found_in_use();
269     lastVolume[0] = 0;
270     for (int vol_index=1;  vol_index < 20; vol_index++) {
271        bash_spaces(dcr->media_type);
272        bash_spaces(dcr->pool_name);
273        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
274        unbash_spaces(dcr->media_type);
275        unbash_spaces(dcr->pool_name);
276        Dmsg1(100, ">dird %s", dir->msg);
277        if (do_get_volume_info(dcr)) {
278           /* Give up if we get the same volume name twice */
279           if (lastVolume[0] && strcmp(lastVolume, dcr->VolumeName) == 0) {
280              Dmsg1(100, "Got same vol = %s\n", lastVolume);
281              break;
282           }
283           bstrncpy(lastVolume, dcr->VolumeName, sizeof(lastVolume));
284           if (dcr->can_i_write_volume()) {
285              Dmsg1(100, "Call reserve_volume for write. Vol=%s\n", dcr->VolumeName);
286              if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
287                 Dmsg2(100, "Could not reserve volume %s on %s\n", dcr->VolumeName,
288                     dcr->dev->print_name());
289                 continue;
290              }
291              Dmsg1(100, "dir_find_next_appendable_volume return true. vol=%s\n",
292                 dcr->VolumeName);
293              rtn = true;
294              goto get_out;
295           } else {
296              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
297              /* If volume is not usable, it is in use by someone else */
298              dcr->set_found_in_use();
299              continue;
300           }
301        }
302        Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
303           dcr->dev->print_name());
304        break;
305     }
306     rtn = false;
307     dcr->VolumeName[0] = 0;
308
309 get_out:
310     V(vol_info_mutex);
311     unlock_volumes();
312     return rtn;
313 }
314
315
316 /**
317  * After writing a Volume, send the updated statistics
318  * back to the director. The information comes from the
319  * dev record.
320  */
321 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
322 {
323    JCR *jcr = dcr->jcr;
324    BSOCK *dir = jcr->dir_bsock;
325    DEVICE *dev = dcr->dev;
326    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
327    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
328    int InChanger;
329    bool ok = false;
330    POOL_MEM VolumeName;
331
332    /* If system job, do not update catalog */
333    if (jcr->getJobType() == JT_SYSTEM) {
334       return true;
335    }
336
337    if (vol->VolCatName[0] == 0) {
338       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
339       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
340       return false;
341    }
342
343    /* Lock during Volume update */
344    P(vol_info_mutex);
345    Dmsg1(100, "Update cat VolBytes=%lld\n", vol->VolCatBytes);
346    /* Just labeled or relabeled the tape */
347    if (label) {
348       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
349    }
350 // if (update_LastWritten) {
351       vol->VolLastWritten = time(NULL);
352 // }
353    pm_strcpy(VolumeName, vol->VolCatName);
354    bash_spaces(VolumeName);
355    InChanger = vol->InChanger;
356    dir->fsend(Update_media, jcr->Job,
357       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
358       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
359       vol->VolCatMounts, vol->VolCatErrors,
360       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
361       edit_uint64(vol->VolLastWritten, ed6), 
362       vol->VolCatStatus, vol->Slot, label,
363       InChanger,                      /* bool in structure */
364       edit_int64(vol->VolReadTime, ed3),
365       edit_int64(vol->VolWriteTime, ed4),
366       edit_uint64(vol->VolFirstWritten, ed5),
367       vol->VolCatParts);
368     Dmsg1(100, ">dird %s", dir->msg);
369
370    /* Do not lock device here because it may be locked from label */
371    if (!jcr->is_canceled()) {
372       if (!do_get_volume_info(dcr)) {
373          Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
374          Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
375             vol->VolCatName, jcr->errmsg);
376          goto bail_out;
377       }
378       Dmsg1(420, "get_volume_info() %s", dir->msg);
379       /* Update dev Volume info in case something changed (e.g. expired) */
380       dev->VolCatInfo = dcr->VolCatInfo;
381       ok = true;
382    }
383
384 bail_out:
385    V(vol_info_mutex);
386    return ok;
387 }
388
389 /**
390  * After writing a Volume, create the JobMedia record.
391  */
392 bool dir_create_jobmedia_record(DCR *dcr, bool zero)
393 {
394    JCR *jcr = dcr->jcr;
395    BSOCK *dir = jcr->dir_bsock;
396    char ed1[50];
397
398    /* If system job, do not update catalog */
399    if (jcr->getJobType() == JT_SYSTEM) {
400       return true;
401    }
402
403    /* Throw out records where FI is zero -- i.e. nothing done */
404    if (!zero && dcr->VolFirstIndex == 0 && 
405         (dcr->StartBlock != 0 || dcr->EndBlock != 0)) {
406       Dmsg0(100, "JobMedia FI=0 StartBlock!=0 record suppressed\n");
407       return true;
408    }
409
410    if (!dcr->WroteVol) {
411       return true;                    /* nothing written to tape */
412    }
413
414    dcr->WroteVol = false;
415    if (zero) {
416       /* Send dummy place holder to avoid purging */
417       dir->fsend(Create_job_media, jcr->Job,
418          0 , 0, 0, 0, 0, 0, 0, 0, edit_uint64(dcr->VolMediaId, ed1));
419    } else {
420       dir->fsend(Create_job_media, jcr->Job,
421          dcr->VolFirstIndex, dcr->VolLastIndex,
422          dcr->StartFile, dcr->EndFile,
423          dcr->StartBlock, dcr->EndBlock, 
424          dcr->Copy, dcr->Stripe, 
425          edit_uint64(dcr->VolMediaId, ed1));
426    }
427    Dmsg1(100, ">dird %s", dir->msg);
428    if (dir->recv() <= 0) {
429       Dmsg0(190, "create_jobmedia error bnet_recv\n");
430       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
431            dir->bstrerror());
432       return false;
433    }
434    Dmsg1(100, "<dird %s", dir->msg);
435    if (strcmp(dir->msg, OK_create) != 0) {
436       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
437       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
438       return false;
439    }
440    return true;
441 }
442
443
444 /**
445  * Update File Attribute data
446  * We do the following:
447  *  1. expand the bsock buffer to be large enough 
448  *  2. Write a "header" into the buffer with serialized data
449  *    VolSessionId
450  *    VolSeesionTime
451  *    FileIndex
452  *    Stream
453  *    data length that follows
454  *    start of raw byte data from the Device record.
455  * Note, this is primarily for Attribute data, but can
456  *   also handle any device record. The Director must know
457  *   the raw byte data format that is defined for each Stream.
458  * Now Restore Objects pass through here STREAM_RESTORE_OBJECT
459  */
460 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
461 {
462    JCR *jcr = dcr->jcr;
463    BSOCK *dir = jcr->dir_bsock;
464    ser_declare;
465
466 #ifdef NO_ATTRIBUTES_TEST
467    return true;
468 #endif
469
470    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
471                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
472    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
473                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
474    ser_begin(dir->msg + dir->msglen, 0);
475    ser_uint32(rec->VolSessionId);
476    ser_uint32(rec->VolSessionTime);
477    ser_int32(rec->FileIndex);
478    ser_int32(rec->Stream);
479    ser_uint32(rec->data_len);
480    ser_bytes(rec->data, rec->data_len);
481    dir->msglen = ser_length(dir->msg);
482    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
483    return dir->send();
484 }
485
486
487 /**
488  *   Request the sysop to create an appendable volume
489  *
490  *   Entered with device blocked.
491  *   Leaves with device blocked.
492  *
493  *   Returns: true  on success (operator issues a mount command)
494  *            false on failure
495  *              Note, must create dev->errmsg on error return.
496  *
497  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
498  *      information on suggested volume, but this may not be the
499  *      same as what is actually mounted.
500  *
501  *    When we return with success, the correct tape may or may not
502  *      actually be mounted. The calling routine must read it and
503  *      verify the label.
504  */
505 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
506 {
507    int stat = W_TIMEOUT;
508    DEVICE *dev = dcr->dev;
509    JCR *jcr = dcr->jcr;
510    bool got_vol = false;
511
512    if (job_canceled(jcr)) {
513       return false;
514    }
515    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
516    ASSERT(dev->blocked());
517    for ( ;; ) {
518       if (job_canceled(jcr)) {
519          Mmsg(dev->errmsg,
520               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
521               jcr->Job, dev->print_name());
522          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
523          return false;
524       }
525       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
526       if (got_vol) {
527          goto get_out;
528       } else {
529          if (stat == W_TIMEOUT || stat == W_MOUNT) {
530             Mmsg(dev->errmsg, _(
531 "Job %s is waiting. Cannot find any appendable volumes.\n"
532 "Please use the \"label\" command to create a new Volume for:\n"
533 "    Storage:      %s\n"
534 "    Pool:         %s\n"
535 "    Media type:   %s\n"),
536                jcr->Job,
537                dev->print_name(),
538                dcr->pool_name,
539                dcr->media_type);
540             Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
541             Dmsg1(100, "%s", dev->errmsg);
542          }
543       }
544
545       jcr->sendJobStatus(JS_WaitMedia);
546
547       stat = wait_for_sysop(dcr);
548       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
549       if (dev->poll) {
550          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
551          continue;
552       }
553
554       if (stat == W_TIMEOUT) {
555          if (!double_dev_wait_time(dev)) {
556             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
557                dev->print_name(), jcr->Job);
558             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
559             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
560             return false;             /* exceeded maximum waits */
561          }
562          continue;
563       }
564       if (stat == W_ERROR) {
565          berrno be;
566          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
567          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
568          return false;
569       }
570       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
571    }
572
573 get_out:
574    jcr->sendJobStatus(JS_Running);
575    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
576    return true;
577 }
578
579 /**
580  *   Request to mount specific Volume
581  *
582  *   Entered with device blocked and dcr->VolumeName is desired
583  *      volume.
584  *   Leaves with device blocked.
585  *
586  *   Returns: true  on success (operator issues a mount command)
587  *            false on failure
588  *                  Note, must create dev->errmsg on error return.
589  *
590  */
591 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode)
592 {
593    int stat = W_TIMEOUT;
594    DEVICE *dev = dcr->dev;
595    JCR *jcr = dcr->jcr;
596
597    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
598    if (!dcr->VolumeName[0]) {
599       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
600       return false;
601    }
602    ASSERT(dev->blocked());
603    for ( ;; ) {
604       if (job_canceled(jcr)) {
605          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
606               jcr->Job, dev->print_name());
607          return false;
608       }
609
610       if (dev->is_dvd()) {   
611          dev->unmount(0);
612       }
613       
614       /*
615        * If we are not polling, and the wait timeout or the
616        *   user explicitly did a mount, send him the message.
617        *   Otherwise skip it.
618        */
619       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
620          char *msg;
621          if (mode == ST_APPEND) {
622             msg = _("Please mount Volume \"%s\" or label a new one for:\n"
623               "    Job:          %s\n"
624               "    Storage:      %s\n"
625               "    Pool:         %s\n"
626               "    Media type:   %s\n");
627          } else {
628             msg = _("Please mount Volume \"%s\" for:\n"
629               "    Job:          %s\n"
630               "    Storage:      %s\n"
631               "    Pool:         %s\n"
632               "    Media type:   %s\n");
633          }
634          Jmsg(jcr, M_MOUNT, 0, msg, 
635               dcr->VolumeName,
636               jcr->Job,
637               dev->print_name(),
638               dcr->pool_name,
639               dcr->media_type);
640          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
641                dcr->VolumeName, dev->print_name(), jcr->Job);
642       }
643
644       jcr->sendJobStatus(JS_WaitMount);
645
646       stat = wait_for_sysop(dcr);          /* wait on device */
647       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
648       if (dev->poll) {
649          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
650          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
651          goto get_out;
652       }
653
654       if (stat == W_TIMEOUT) {
655          if (!double_dev_wait_time(dev)) {
656             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
657                dev->print_name(), jcr->Job);
658             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
659             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
660             return false;             /* exceeded maximum waits */
661          }
662          continue;
663       }
664       if (stat == W_ERROR) {
665          berrno be;
666          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
667          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
668          return false;
669       }
670       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
671       break;
672    }
673
674 get_out:
675    jcr->sendJobStatus(JS_Running);
676    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
677    return true;
678 }