]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Remove debug code
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 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 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  *   Version $Id$
35  */
36
37 #include "bacula.h"                   /* pull in global headers */
38 #include "stored.h"                   /* pull in Storage Deamon headers */
39
40 /* Requests sent to the Director */
41 static char Find_media[]   = "CatReq Job=%s FindMedia=%d pool_name=%s media_type=%s\n";
42 static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
43 static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
44    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
45    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
46    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
47    " VolFirstWritten=%s VolParts=%u\n";
48 static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
49    " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u"
50    " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%s\n";
51 static char FileAttributes[] = "UpdCat Job=%s FileAttributes ";
52 static char Job_status[]     = "Status Job=%s JobStatus=%d\n";
53
54 /* Responses received from the Director */
55 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
56    " VolBlocks=%lu VolBytes=%lld VolMounts=%lu VolErrors=%lu VolWrites=%lu"
57    " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s"
58    " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
59    " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
60    " VolParts=%lu LabelType=%ld MediaId=%lld\n";
61
62
63 static char OK_create[] = "1000 OK CreateJobMedia\n";
64
65 static pthread_mutex_t vol_info_mutex = PTHREAD_MUTEX_INITIALIZER;
66
67 #ifdef needed
68
69 static char Device_update[] = "DevUpd Job=%s device=%s "
70    "append=%d read=%d num_writers=%d "
71    "open=%d labeled=%d offline=%d "
72    "reserved=%d max_writers=%d "
73    "autoselect=%d autochanger=%d "
74    "changer_name=%s media_type=%s volume_name=%s\n";
75
76
77 /* Send update information about a device to Director */
78 bool dir_update_device(JCR *jcr, DEVICE *dev)
79 {
80    BSOCK *dir = jcr->dir_bsock;
81    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
82    DEVRES *device = dev->device;
83    bool ok;
84    
85    pm_strcpy(dev_name, device->hdr.name);
86    bash_spaces(dev_name);
87    if (dev->is_labeled()) {
88       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
89    } else {
90       pm_strcpy(VolumeName, "*");
91    }
92    bash_spaces(VolumeName);
93    pm_strcpy(MediaType, device->media_type);
94    bash_spaces(MediaType);
95    if (device->changer_res) {
96       pm_strcpy(ChangerName, device->changer_res->hdr.name);
97       bash_spaces(ChangerName);
98    } else {
99       pm_strcpy(ChangerName, "*");
100    }
101    ok = dir->fsend(Device_update, 
102       jcr->Job,
103       dev_name.c_str(),
104       dev->can_append()!=0,
105       dev->can_read()!=0, dev->num_writers, 
106       dev->is_open()!=0, dev->is_labeled()!=0,
107       dev->is_offline()!=0, dev->reserved_device, 
108       dev->is_tape()?100000:1,
109       dev->autoselect, 0, 
110       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
111    Dmsg1(100, ">dird: %s\n", dir->msg);
112    return ok;
113 }
114
115 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
116 {
117    BSOCK *dir = jcr->dir_bsock;
118    POOL_MEM dev_name, MediaType;
119    DEVRES *device;
120    bool ok;
121
122    pm_strcpy(dev_name, changer->hdr.name);
123    bash_spaces(dev_name);
124    device = (DEVRES *)changer->device->first();
125    pm_strcpy(MediaType, device->media_type);
126    bash_spaces(MediaType);
127    /* This is mostly to indicate that we are here */
128    ok = dir->fsend(Device_update,
129       jcr->Job,
130       dev_name.c_str(),         /* Changer name */
131       0, 0, 0,                  /* append, read, num_writers */
132       0, 0, 0,                  /* is_open, is_labeled, offline */
133       0, 0,                     /* reserved, max_writers */
134       0,                        /* Autoselect */
135       changer->device->size(),  /* Number of devices */
136       "0",                      /* PoolId */
137       "*",                      /* ChangerName */
138       MediaType.c_str(),        /* MediaType */
139       "*");                     /* VolName */
140    Dmsg1(100, ">dird: %s\n", dir->msg);
141    return ok;
142 }
143 #endif
144
145
146 /*
147  * Send current JobStatus to Director
148  */
149 bool dir_send_job_status(JCR *jcr)
150 {
151    return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus);
152 }
153
154 /*
155  * Common routine for:
156  *   dir_get_volume_info()
157  * and
158  *   dir_find_next_appendable_volume()
159  *
160  *  NOTE!!! All calls to this routine must be protected by
161  *          locking vol_info_mutex before calling it so that
162  *          we don't have one thread modifying the parameters
163  *          and another reading them.
164  *
165  *  Returns: true  on success and vol info in dcr->VolCatInfo
166  *           false on failure
167  */
168 static bool do_get_volume_info(DCR *dcr)
169 {
170     JCR *jcr = dcr->jcr;
171     BSOCK *dir = jcr->dir_bsock;
172     VOLUME_CAT_INFO vol;
173     int n;
174     int32_t InChanger;
175
176     if (dir->recv() <= 0) {
177        Dmsg0(200, "getvolname error bnet_recv\n");
178        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
179        return false;
180     }
181     memset(&vol, 0, sizeof(vol));
182     Dmsg1(100, "<dird %s", dir->msg);
183     n = sscanf(dir->msg, OK_media, vol.VolCatName,
184                &vol.VolCatJobs, &vol.VolCatFiles,
185                &vol.VolCatBlocks, &vol.VolCatBytes,
186                &vol.VolCatMounts, &vol.VolCatErrors,
187                &vol.VolCatWrites, &vol.VolCatMaxBytes,
188                &vol.VolCatCapacityBytes, vol.VolCatStatus,
189                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
190                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
191                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
192                &vol.LabelType, &vol.VolMediaId);
193     if (n != 22) {
194        Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
195              n, dir->msglen, dir->msg);
196        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
197        return false;
198     }
199     vol.InChanger = InChanger;        /* bool in structure */
200     unbash_spaces(vol.VolCatName);
201     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
202     dcr->VolCatInfo = vol;            /* structure assignment */
203
204     Dmsg2(100, "do_reqest_vol_info return true slot=%d Volume=%s\n",
205           vol.Slot, vol.VolCatName);
206     return true;
207 }
208
209
210 /*
211  * Get Volume info for a specific volume from the Director's Database
212  *
213  * Returns: true  on success   (Director guarantees that Pool and MediaType
214  *                              are correct and VolStatus==Append or
215  *                              VolStatus==Recycle)
216  *          false on failure
217  *
218  *          Volume information returned in dcr->VolCatInfo
219  */
220 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
221 {
222     JCR *jcr = dcr->jcr;
223     BSOCK *dir = jcr->dir_bsock;
224
225     P(vol_info_mutex);
226     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
227     bash_spaces(dcr->VolCatInfo.VolCatName);
228     dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
229        writing==GET_VOL_INFO_FOR_WRITE?1:0);
230     Dmsg1(100, ">dird %s", dir->msg);
231     unbash_spaces(dcr->VolCatInfo.VolCatName);
232     bool ok = do_get_volume_info(dcr);
233     V(vol_info_mutex);
234     return ok;
235 }
236
237
238
239 /*
240  * Get info on the next appendable volume in the Director's database
241  *
242  * Returns: true  on success dcr->VolumeName is volume
243  *                reserve_volume() called on Volume name
244  *          false on failure dcr->VolumeName[0] == 0
245  *                also sets dcr->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. 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 VolFiles=%d\n", dev->file);
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 (!do_get_volume_info(dcr)) {
372       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
373       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
374          vol->VolCatName, jcr->errmsg);
375       goto bail_out;
376    }
377    Dmsg1(420, "get_volume_info() %s", dir->msg);
378    /* Update dev Volume info in case something changed (e.g. expired) */
379    dev->VolCatInfo = dcr->VolCatInfo;
380    ok = true;
381
382 bail_out:
383    V(vol_info_mutex);
384    return ok;
385 }
386
387 /*
388  * After writing a Volume, create the JobMedia record.
389  */
390 bool dir_create_jobmedia_record(DCR *dcr, bool zero)
391 {
392    JCR *jcr = dcr->jcr;
393    BSOCK *dir = jcr->dir_bsock;
394    char ed1[50];
395
396    /* If system job, do not update catalog */
397    if (jcr->getJobType() == JT_SYSTEM) {
398       return true;
399    }
400
401    /* Throw out records where FI is zero -- i.e. nothing done */
402    if (!zero && dcr->VolFirstIndex == 0 && 
403         (dcr->StartBlock != 0 || dcr->EndBlock != 0)) {
404       Dmsg0(100, "JobMedia FI=0 StartBlock!=0 record suppressed\n");
405       return true;
406    }
407
408    if (!dcr->WroteVol) {
409       return true;                    /* nothing written to tape */
410    }
411
412    dcr->WroteVol = false;
413    if (zero) {
414       /* Send dummy place holder to avoid purging */
415       dir->fsend(Create_job_media, jcr->Job,
416          0 , 0, 0, 0, 0, 0, 0, 0, edit_uint64(dcr->VolMediaId, ed1));
417    } else {
418       dir->fsend(Create_job_media, jcr->Job,
419          dcr->VolFirstIndex, dcr->VolLastIndex,
420          dcr->StartFile, dcr->EndFile,
421          dcr->StartBlock, dcr->EndBlock, 
422          dcr->Copy, dcr->Stripe, 
423          edit_uint64(dcr->VolMediaId, ed1));
424    }
425    Dmsg1(100, ">dird %s", dir->msg);
426    if (dir->recv() <= 0) {
427       Dmsg0(190, "create_jobmedia error bnet_recv\n");
428       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
429            dir->bstrerror());
430       return false;
431    }
432    Dmsg1(100, "<dird %s", dir->msg);
433    if (strcmp(dir->msg, OK_create) != 0) {
434       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
435       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
436       return false;
437    }
438    return true;
439 }
440
441
442 /*
443  * Update File Attribute data
444  */
445 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
446 {
447    JCR *jcr = dcr->jcr;
448    BSOCK *dir = jcr->dir_bsock;
449    ser_declare;
450
451 #ifdef NO_ATTRIBUTES_TEST
452    return true;
453 #endif
454
455    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
456                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
457    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
458                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
459    ser_begin(dir->msg + dir->msglen, 0);
460    ser_uint32(rec->VolSessionId);
461    ser_uint32(rec->VolSessionTime);
462    ser_int32(rec->FileIndex);
463    ser_int32(rec->Stream);
464    ser_uint32(rec->data_len);
465    ser_bytes(rec->data, rec->data_len);
466    dir->msglen = ser_length(dir->msg);
467    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
468    if (rec->Stream == STREAM_UNIX_ATTRIBUTES || 
469        rec->Stream == STREAM_UNIX_ATTRIBUTES_EX) {
470       dir->set_data_end();                 /* set offset of last valid data */
471    }
472    return dir->send();
473 }
474
475
476 /*
477  *   Request the sysop to create an appendable volume
478  *
479  *   Entered with device blocked.
480  *   Leaves with device blocked.
481  *
482  *   Returns: true  on success (operator issues a mount command)
483  *            false on failure
484  *              Note, must create dev->errmsg on error return.
485  *
486  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
487  *      information on suggested volume, but this may not be the
488  *      same as what is actually mounted.
489  *
490  *    When we return with success, the correct tape may or may not
491  *      actually be mounted. The calling routine must read it and
492  *      verify the label.
493  */
494 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
495 {
496    int stat = W_TIMEOUT;
497    DEVICE *dev = dcr->dev;
498    JCR *jcr = dcr->jcr;
499    bool got_vol = false;
500
501    if (job_canceled(jcr)) {
502       return false;
503    }
504    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
505    ASSERT(dev->blocked());
506    for ( ;; ) {
507       if (job_canceled(jcr)) {
508          Mmsg(dev->errmsg,
509               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
510               jcr->Job, dev->print_name());
511          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
512          return false;
513       }
514       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
515       if (got_vol) {
516          goto get_out;
517       } else {
518          if (stat == W_TIMEOUT || stat == W_MOUNT) {
519             Mmsg(dev->errmsg, _(
520 "Job %s is waiting. Cannot find any appendable volumes.\n"
521 "Please use the \"label\" command to create a new Volume for:\n"
522 "    Storage:      %s\n"
523 "    Pool:         %s\n"
524 "    Media type:   %s\n"),
525                jcr->Job,
526                dev->print_name(),
527                dcr->pool_name,
528                dcr->media_type);
529             Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
530             Dmsg1(100, "%s", dev->errmsg);
531          }
532       }
533
534       set_jcr_job_status(jcr, JS_WaitMedia);
535       dir_send_job_status(jcr);
536
537       stat = wait_for_sysop(dcr);
538       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
539       if (dev->poll) {
540          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
541          continue;
542       }
543
544       if (stat == W_TIMEOUT) {
545          if (!double_dev_wait_time(dev)) {
546             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
547                dev->print_name(), jcr->Job);
548             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
549             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
550             return false;             /* exceeded maximum waits */
551          }
552          continue;
553       }
554       if (stat == W_ERROR) {
555          berrno be;
556          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
557          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
558          return false;
559       }
560       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
561    }
562
563 get_out:
564    set_jcr_job_status(jcr, JS_Running);
565    dir_send_job_status(jcr);
566    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
567    return true;
568 }
569
570 /*
571  *   Request to mount specific Volume
572  *
573  *   Entered with device blocked and dcr->VolumeName is desired
574  *      volume.
575  *   Leaves with device blocked.
576  *
577  *   Returns: true  on success (operator issues a mount command)
578  *            false on failure
579  *                  Note, must create dev->errmsg on error return.
580  *
581  */
582 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode)
583 {
584    int stat = W_TIMEOUT;
585    DEVICE *dev = dcr->dev;
586    JCR *jcr = dcr->jcr;
587
588    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
589    if (!dcr->VolumeName[0]) {
590       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
591       return false;
592    }
593    ASSERT(dev->blocked());
594    for ( ;; ) {
595       if (job_canceled(jcr)) {
596          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
597               jcr->Job, dev->print_name());
598          return false;
599       }
600
601       if (dev->is_dvd()) {   
602          dev->unmount(0);
603       }
604       
605       /*
606        * If we are not polling, and the wait timeout or the
607        *   user explicitly did a mount, send him the message.
608        *   Otherwise skip it.
609        */
610       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
611          char *msg;
612          if (mode == ST_APPEND) {
613             msg = _("Please mount Volume \"%s\" or label a new one for:\n"
614               "    Job:          %s\n"
615               "    Storage:      %s\n"
616               "    Pool:         %s\n"
617               "    Media type:   %s\n");
618          } else {
619             msg = _("Please mount Volume \"%s\" for:\n"
620               "    Job:          %s\n"
621               "    Storage:      %s\n"
622               "    Pool:         %s\n"
623               "    Media type:   %s\n");
624          }
625          Jmsg(jcr, M_MOUNT, 0, msg, 
626               dcr->VolumeName,
627               jcr->Job,
628               dev->print_name(),
629               dcr->pool_name,
630               dcr->media_type);
631          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
632                dcr->VolumeName, dev->print_name(), jcr->Job);
633       }
634
635       set_jcr_job_status(jcr, JS_WaitMount);
636       dir_send_job_status(jcr);
637
638       stat = wait_for_sysop(dcr);          /* wait on device */
639       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
640       if (dev->poll) {
641          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
642          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
643          goto get_out;
644       }
645
646       if (stat == W_TIMEOUT) {
647          if (!double_dev_wait_time(dev)) {
648             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
649                dev->print_name(), jcr->Job);
650             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
651             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
652             return false;             /* exceeded maximum waits */
653          }
654          continue;
655       }
656       if (stat == W_ERROR) {
657          berrno be;
658          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
659          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
660          return false;
661       }
662       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
663       break;
664    }
665
666 get_out:
667    set_jcr_job_status(jcr, JS_Running);
668    dir_send_job_status(jcr);
669    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
670    return true;
671 }