]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Rewrite some SD subroutines as class members
[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 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    return dir->send();
483 }
484
485
486 /**
487  *   Request the sysop to create an appendable volume
488  *
489  *   Entered with device blocked.
490  *   Leaves with device blocked.
491  *
492  *   Returns: true  on success (operator issues a mount command)
493  *            false on failure
494  *              Note, must create dev->errmsg on error return.
495  *
496  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
497  *      information on suggested volume, but this may not be the
498  *      same as what is actually mounted.
499  *
500  *    When we return with success, the correct tape may or may not
501  *      actually be mounted. The calling routine must read it and
502  *      verify the label.
503  */
504 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
505 {
506    int stat = W_TIMEOUT;
507    DEVICE *dev = dcr->dev;
508    JCR *jcr = dcr->jcr;
509    bool got_vol = false;
510
511    if (job_canceled(jcr)) {
512       return false;
513    }
514    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
515    ASSERT(dev->blocked());
516    for ( ;; ) {
517       if (job_canceled(jcr)) {
518          Mmsg(dev->errmsg,
519               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
520               jcr->Job, dev->print_name());
521          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
522          return false;
523       }
524       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
525       if (got_vol) {
526          goto get_out;
527       } else {
528          if (stat == W_TIMEOUT || stat == W_MOUNT) {
529             Mmsg(dev->errmsg, _(
530 "Job %s is waiting. Cannot find any appendable volumes.\n"
531 "Please use the \"label\" command to create a new Volume for:\n"
532 "    Storage:      %s\n"
533 "    Pool:         %s\n"
534 "    Media type:   %s\n"),
535                jcr->Job,
536                dev->print_name(),
537                dcr->pool_name,
538                dcr->media_type);
539             Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
540             Dmsg1(100, "%s", dev->errmsg);
541          }
542       }
543
544       jcr->setJobStatus(JS_WaitMedia);
545       dir_send_job_status(jcr);
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->setJobStatus(JS_Running);
575    dir_send_job_status(jcr);
576    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
577    return true;
578 }
579
580 /**
581  *   Request to mount specific Volume
582  *
583  *   Entered with device blocked and dcr->VolumeName is desired
584  *      volume.
585  *   Leaves with device blocked.
586  *
587  *   Returns: true  on success (operator issues a mount command)
588  *            false on failure
589  *                  Note, must create dev->errmsg on error return.
590  *
591  */
592 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode)
593 {
594    int stat = W_TIMEOUT;
595    DEVICE *dev = dcr->dev;
596    JCR *jcr = dcr->jcr;
597
598    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
599    if (!dcr->VolumeName[0]) {
600       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
601       return false;
602    }
603    ASSERT(dev->blocked());
604    for ( ;; ) {
605       if (job_canceled(jcr)) {
606          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
607               jcr->Job, dev->print_name());
608          return false;
609       }
610
611       if (dev->is_dvd()) {   
612          dev->unmount(0);
613       }
614       
615       /*
616        * If we are not polling, and the wait timeout or the
617        *   user explicitly did a mount, send him the message.
618        *   Otherwise skip it.
619        */
620       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
621          char *msg;
622          if (mode == ST_APPEND) {
623             msg = _("Please mount Volume \"%s\" or label a new one for:\n"
624               "    Job:          %s\n"
625               "    Storage:      %s\n"
626               "    Pool:         %s\n"
627               "    Media type:   %s\n");
628          } else {
629             msg = _("Please mount Volume \"%s\" for:\n"
630               "    Job:          %s\n"
631               "    Storage:      %s\n"
632               "    Pool:         %s\n"
633               "    Media type:   %s\n");
634          }
635          Jmsg(jcr, M_MOUNT, 0, msg, 
636               dcr->VolumeName,
637               jcr->Job,
638               dev->print_name(),
639               dcr->pool_name,
640               dcr->media_type);
641          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
642                dcr->VolumeName, dev->print_name(), jcr->Job);
643       }
644
645       jcr->setJobStatus(JS_WaitMount);
646       dir_send_job_status(jcr);
647
648       stat = wait_for_sysop(dcr);          /* wait on device */
649       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
650       if (dev->poll) {
651          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
652          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
653          goto get_out;
654       }
655
656       if (stat == W_TIMEOUT) {
657          if (!double_dev_wait_time(dev)) {
658             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
659                dev->print_name(), jcr->Job);
660             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
661             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
662             return false;             /* exceeded maximum waits */
663          }
664          continue;
665       }
666       if (stat == W_ERROR) {
667          berrno be;
668          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
669          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
670          return false;
671       }
672       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
673       break;
674    }
675
676 get_out:
677    jcr->setJobStatus(JS_Running);
678    dir_send_job_status(jcr);
679    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
680    return true;
681 }