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