]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
6e13beaa8f88a1a64b1f775c54a19ec970616982
[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 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  */
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  */
446 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
447 {
448    JCR *jcr = dcr->jcr;
449    BSOCK *dir = jcr->dir_bsock;
450    ser_declare;
451
452 #ifdef NO_ATTRIBUTES_TEST
453    return true;
454 #endif
455
456    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
457                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
458    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
459                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
460    ser_begin(dir->msg + dir->msglen, 0);
461    ser_uint32(rec->VolSessionId);
462    ser_uint32(rec->VolSessionTime);
463    ser_int32(rec->FileIndex);
464    ser_int32(rec->Stream);
465    ser_uint32(rec->data_len);
466    ser_bytes(rec->data, rec->data_len);
467    dir->msglen = ser_length(dir->msg);
468    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
469    if (rec->Stream == STREAM_UNIX_ATTRIBUTES || 
470        rec->Stream == STREAM_UNIX_ATTRIBUTES_EX) {
471       dir->set_data_end();                 /* set offset of last valid data */
472    }
473    return dir->send();
474 }
475
476
477 /*
478  *   Request the sysop to create an appendable volume
479  *
480  *   Entered with device blocked.
481  *   Leaves with device blocked.
482  *
483  *   Returns: true  on success (operator issues a mount command)
484  *            false on failure
485  *              Note, must create dev->errmsg on error return.
486  *
487  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
488  *      information on suggested volume, but this may not be the
489  *      same as what is actually mounted.
490  *
491  *    When we return with success, the correct tape may or may not
492  *      actually be mounted. The calling routine must read it and
493  *      verify the label.
494  */
495 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
496 {
497    int stat = W_TIMEOUT;
498    DEVICE *dev = dcr->dev;
499    JCR *jcr = dcr->jcr;
500    bool got_vol = false;
501
502    if (job_canceled(jcr)) {
503       return false;
504    }
505    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
506    ASSERT(dev->blocked());
507    for ( ;; ) {
508       if (job_canceled(jcr)) {
509          Mmsg(dev->errmsg,
510               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
511               jcr->Job, dev->print_name());
512          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
513          return false;
514       }
515       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
516       if (got_vol) {
517          goto get_out;
518       } else {
519          if (stat == W_TIMEOUT || stat == W_MOUNT) {
520             Mmsg(dev->errmsg, _(
521 "Job %s is waiting. Cannot find any appendable volumes.\n"
522 "Please use the \"label\" command to create a new Volume for:\n"
523 "    Storage:      %s\n"
524 "    Pool:         %s\n"
525 "    Media type:   %s\n"),
526                jcr->Job,
527                dev->print_name(),
528                dcr->pool_name,
529                dcr->media_type);
530             Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
531             Dmsg1(100, "%s", dev->errmsg);
532          }
533       }
534
535       set_jcr_job_status(jcr, JS_WaitMedia);
536       dir_send_job_status(jcr);
537
538       stat = wait_for_sysop(dcr);
539       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
540       if (dev->poll) {
541          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
542          continue;
543       }
544
545       if (stat == W_TIMEOUT) {
546          if (!double_dev_wait_time(dev)) {
547             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
548                dev->print_name(), jcr->Job);
549             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
550             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
551             return false;             /* exceeded maximum waits */
552          }
553          continue;
554       }
555       if (stat == W_ERROR) {
556          berrno be;
557          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
558          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
559          return false;
560       }
561       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
562    }
563
564 get_out:
565    set_jcr_job_status(jcr, JS_Running);
566    dir_send_job_status(jcr);
567    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
568    return true;
569 }
570
571 /*
572  *   Request to mount specific Volume
573  *
574  *   Entered with device blocked and dcr->VolumeName is desired
575  *      volume.
576  *   Leaves with device blocked.
577  *
578  *   Returns: true  on success (operator issues a mount command)
579  *            false on failure
580  *                  Note, must create dev->errmsg on error return.
581  *
582  */
583 bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode)
584 {
585    int stat = W_TIMEOUT;
586    DEVICE *dev = dcr->dev;
587    JCR *jcr = dcr->jcr;
588
589    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
590    if (!dcr->VolumeName[0]) {
591       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
592       return false;
593    }
594    ASSERT(dev->blocked());
595    for ( ;; ) {
596       if (job_canceled(jcr)) {
597          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
598               jcr->Job, dev->print_name());
599          return false;
600       }
601
602       if (dev->is_dvd()) {   
603          dev->unmount(0);
604       }
605       
606       /*
607        * If we are not polling, and the wait timeout or the
608        *   user explicitly did a mount, send him the message.
609        *   Otherwise skip it.
610        */
611       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
612          char *msg;
613          if (mode == ST_APPEND) {
614             msg = _("Please mount Volume \"%s\" or label a new one for:\n"
615               "    Job:          %s\n"
616               "    Storage:      %s\n"
617               "    Pool:         %s\n"
618               "    Media type:   %s\n");
619          } else {
620             msg = _("Please mount Volume \"%s\" for:\n"
621               "    Job:          %s\n"
622               "    Storage:      %s\n"
623               "    Pool:         %s\n"
624               "    Media type:   %s\n");
625          }
626          Jmsg(jcr, M_MOUNT, 0, msg, 
627               dcr->VolumeName,
628               jcr->Job,
629               dev->print_name(),
630               dcr->pool_name,
631               dcr->media_type);
632          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
633                dcr->VolumeName, dev->print_name(), jcr->Job);
634       }
635
636       set_jcr_job_status(jcr, JS_WaitMount);
637       dir_send_job_status(jcr);
638
639       stat = wait_for_sysop(dcr);          /* wait on device */
640       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
641       if (dev->poll) {
642          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
643          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
644          goto get_out;
645       }
646
647       if (stat == W_TIMEOUT) {
648          if (!double_dev_wait_time(dev)) {
649             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
650                dev->print_name(), jcr->Job);
651             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
652             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
653             return false;             /* exceeded maximum waits */
654          }
655          continue;
656       }
657       if (stat == W_ERROR) {
658          berrno be;
659          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
660          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
661          return false;
662       }
663       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
664       break;
665    }
666
667 get_out:
668    set_jcr_job_status(jcr, JS_Running);
669    dir_send_job_status(jcr);
670    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
671    return true;
672 }