]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Update copyright
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2  *  Subroutines to handle Catalog reqests sent to the Director
3  *   Reqests/commands from the Director are handled in dircmd.c
4  *
5  *   Kern Sibbald, December 2000
6  *
7  *   Version $Id$
8  */
9 /*
10    Bacula® - The Network Backup Solution
11
12    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
13
14    The main author of Bacula is Kern Sibbald, with contributions from
15    many others, a complete list can be found in the file AUTHORS.
16    This program is Free Software; you can redistribute it and/or
17    modify it under the terms of version two of the GNU General Public
18    License as published by the Free Software Foundation plus additions
19    that are listed in the file LICENSE.
20
21    This program is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24    General Public License for more details.
25
26    You should have received a copy of the GNU General Public License
27    along with this program; if not, write to the Free Software
28    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29    02110-1301, USA.
30
31    Bacula® is a registered trademark of John Walker.
32    The licensor of Bacula is the Free Software Foundation Europe
33    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34    Switzerland, email:ftf@fsfeurope.org.
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=%d 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 #ifdef needed
66
67 static char Device_update[] = "DevUpd Job=%s device=%s "
68    "append=%d read=%d num_writers=%d "
69    "open=%d labeled=%d offline=%d "
70    "reserved=%d max_writers=%d "
71    "autoselect=%d autochanger=%d "
72    "changer_name=%s media_type=%s volume_name=%s\n";
73
74
75 /* Send update information about a device to Director */
76 bool dir_update_device(JCR *jcr, DEVICE *dev)
77 {
78    BSOCK *dir = jcr->dir_bsock;
79    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
80    DEVRES *device = dev->device;
81    bool ok;
82    
83    pm_strcpy(dev_name, device->hdr.name);
84    bash_spaces(dev_name);
85    if (dev->is_labeled()) {
86       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
87    } else {
88       pm_strcpy(VolumeName, "*");
89    }
90    bash_spaces(VolumeName);
91    pm_strcpy(MediaType, device->media_type);
92    bash_spaces(MediaType);
93    if (device->changer_res) {
94       pm_strcpy(ChangerName, device->changer_res->hdr.name);
95       bash_spaces(ChangerName);
96    } else {
97       pm_strcpy(ChangerName, "*");
98    }
99    ok =bnet_fsend(dir, Device_update, 
100       jcr->Job,
101       dev_name.c_str(),
102       dev->can_append()!=0,
103       dev->can_read()!=0, dev->num_writers, 
104       dev->is_open()!=0, dev->is_labeled()!=0,
105       dev->is_offline()!=0, dev->reserved_device, 
106       dev->is_tape()?100000:1,
107       dev->autoselect, 0, 
108       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
109    Dmsg1(100, ">dird: %s\n", dir->msg);
110    return ok;
111 }
112
113 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
114 {
115    BSOCK *dir = jcr->dir_bsock;
116    POOL_MEM dev_name, MediaType;
117    DEVRES *device;
118    bool ok;
119
120    pm_strcpy(dev_name, changer->hdr.name);
121    bash_spaces(dev_name);
122    device = (DEVRES *)changer->device->first();
123    pm_strcpy(MediaType, device->media_type);
124    bash_spaces(MediaType);
125    /* This is mostly to indicate that we are here */
126    ok = bnet_fsend(dir, Device_update,
127       jcr->Job,
128       dev_name.c_str(),         /* Changer name */
129       0, 0, 0,                  /* append, read, num_writers */
130       0, 0, 0,                  /* is_open, is_labeled, offline */
131       0, 0,                     /* reserved, max_writers */
132       0,                        /* Autoselect */
133       changer->device->size(),  /* Number of devices */
134       "0",                      /* PoolId */
135       "*",                      /* ChangerName */
136       MediaType.c_str(),        /* MediaType */
137       "*");                     /* VolName */
138    Dmsg1(100, ">dird: %s\n", dir->msg);
139    return ok;
140 }
141 #endif
142
143
144 /*
145  * Send current JobStatus to Director
146  */
147 bool dir_send_job_status(JCR *jcr)
148 {
149    return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
150 }
151
152 /*
153  * Common routine for:
154  *   dir_get_volume_info()
155  * and
156  *   dir_find_next_appendable_volume()
157  *
158  *  Returns: true  on success and vol info in dcr->VolCatInfo
159  *           false on failure
160  */
161 static bool do_get_volume_info(DCR *dcr)
162 {
163     JCR *jcr = dcr->jcr;
164     BSOCK *dir = jcr->dir_bsock;
165     VOLUME_CAT_INFO vol;
166     int n;
167     int32_t InChanger;
168
169     dcr->VolumeName[0] = 0;           /* No volume */
170     if (bnet_recv(dir) <= 0) {
171        Dmsg0(200, "getvolname error bnet_recv\n");
172        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
173        return false;
174     }
175     memset(&vol, 0, sizeof(vol));
176     Dmsg1(100, "<dird %s", dir->msg);
177     n = sscanf(dir->msg, OK_media, vol.VolCatName,
178                &vol.VolCatJobs, &vol.VolCatFiles,
179                &vol.VolCatBlocks, &vol.VolCatBytes,
180                &vol.VolCatMounts, &vol.VolCatErrors,
181                &vol.VolCatWrites, &vol.VolCatMaxBytes,
182                &vol.VolCatCapacityBytes, vol.VolCatStatus,
183                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
184                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
185                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
186                &vol.LabelType, &vol.VolMediaId);
187     if (n != 22) {
188        Dmsg2(100, "Bad response from Dir fields=%d: %s", n, dir->msg);
189        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
190        return false;
191     }
192     vol.InChanger = InChanger;        /* bool in structure */
193     unbash_spaces(vol.VolCatName);
194     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
195     dcr->VolCatInfo = vol;            /* structure assignment */
196
197     Dmsg2(100, "do_reqest_vol_info return true slot=%d Volume=%s\n",
198           vol.Slot, vol.VolCatName);
199     return true;
200 }
201
202
203 /*
204  * Get Volume info for a specific volume from the Director's Database
205  *
206  * Returns: true  on success   (Director guarantees that Pool and MediaType
207  *                              are correct and VolStatus==Append or
208  *                              VolStatus==Recycle)
209  *          false on failure
210  *
211  *          Volume information returned in dcr->VolCatInfo
212  */
213 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
214 {
215     JCR *jcr = dcr->jcr;
216     BSOCK *dir = jcr->dir_bsock;
217
218     bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
219     bash_spaces(dcr->VolCatInfo.VolCatName);
220     bnet_fsend(dir, Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
221        writing==GET_VOL_INFO_FOR_WRITE?1:0);
222     Dmsg1(100, ">dird: %s", dir->msg);
223     bool ok = do_get_volume_info(dcr);
224     return ok;
225 }
226
227
228
229 /*
230  * Get info on the next appendable volume in the Director's database
231  * Returns: true  on success
232  *          false on failure
233  *
234  *          Volume information returned in dcr
235  *
236  */
237 bool dir_find_next_appendable_volume(DCR *dcr)
238 {
239     JCR *jcr = dcr->jcr;
240     BSOCK *dir = jcr->dir_bsock;
241     bool found = false;
242
243     Dmsg0(200, "dir_find_next_appendable_volume\n");
244     /*
245      * Try the twenty oldest or most available volumes.  Note,
246      *   the most available could already be mounted on another
247      *   drive, so we continue looking for a not in use Volume.
248      */
249     lock_reservations();
250     for (int vol_index=1;  vol_index < 20; vol_index++) {
251        bash_spaces(dcr->media_type);
252        bash_spaces(dcr->pool_name);
253        bnet_fsend(dir, Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
254        unbash_spaces(dcr->media_type);
255        unbash_spaces(dcr->pool_name);
256        Dmsg1(100, ">dird: %s", dir->msg);
257        bool ok = do_get_volume_info(dcr);
258        if (ok) {
259           if (dcr->any_volume || !is_volume_in_use(dcr)) {
260              found = true;
261              break;
262           } else {
263              Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
264              continue;
265           }
266        } else {
267           Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
268              dcr->dev->print_name());
269           found = false;
270           break;
271        }
272     }
273     if (found) {
274        Dmsg0(400, "dir_find_next_appendable_volume return true\n");
275        new_volume(dcr, dcr->VolumeName);   /* reserve volume */
276        unlock_reservations();
277        return true;
278     }
279     dcr->VolumeName[0] = 0;
280     unlock_reservations();
281     return false;
282 }
283
284
285 /*
286  * After writing a Volume, send the updated statistics
287  * back to the director. The information comes from the
288  * dev record.
289  */
290 bool dir_update_volume_info(DCR *dcr, bool label)
291 {
292    JCR *jcr = dcr->jcr;
293    BSOCK *dir = jcr->dir_bsock;
294    DEVICE *dev = dcr->dev;
295    time_t LastWritten = time(NULL);
296    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
297    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
298    int InChanger;
299    POOL_MEM VolumeName;
300
301    /* If system job, do not update catalog */
302    if (jcr->JobType == JT_SYSTEM) {
303       return true;
304    }
305
306    if (vol->VolCatName[0] == 0) {
307       Jmsg0(jcr, M_FATAL, 0, _("NULL Volume name. This shouldn't happen!!!\n"));
308       Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
309       return false;
310    }
311    if (dev->can_read()) {
312       Jmsg0(jcr, M_FATAL, 0, _("Attempt to update_volume_info in read mode!!!\n"));
313       Pmsg0(000, _("Attempt to update_volume_info in read mode!!!\n"));
314       return false;
315    }
316
317    Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
318    /* Just labeled or relabeled the tape */
319    if (label) {
320       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
321    }
322    pm_strcpy(VolumeName, vol->VolCatName);
323    bash_spaces(VolumeName);
324    InChanger = vol->InChanger;
325    bnet_fsend(dir, Update_media, jcr->Job,
326       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
327       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
328       vol->VolCatMounts, vol->VolCatErrors,
329       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
330       LastWritten, vol->VolCatStatus, vol->Slot, label,
331       InChanger,                      /* bool in structure */
332       edit_uint64(vol->VolReadTime, ed3),
333       edit_uint64(vol->VolWriteTime, ed4),
334       edit_uint64(vol->VolFirstWritten, ed5),
335       vol->VolCatParts);
336     Dmsg1(100, ">dird: %s", dir->msg);
337
338    /* Do not lock device here because it may be locked from label */
339    if (!do_get_volume_info(dcr)) {
340       Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
341       Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"), 
342          vol->VolCatName, jcr->errmsg);
343       return false;
344    }
345    Dmsg1(420, "get_volume_info(): %s", dir->msg);
346    /* Update dev Volume info in case something changed (e.g. expired) */
347    dev->VolCatInfo = dcr->VolCatInfo;
348    return true;
349 }
350
351 /*
352  * After writing a Volume, create the JobMedia record.
353  */
354 bool dir_create_jobmedia_record(DCR *dcr)
355 {
356    JCR *jcr = dcr->jcr;
357    BSOCK *dir = jcr->dir_bsock;
358    char ed1[50];
359
360    /* If system job, do not update catalog */
361    if (jcr->JobType == JT_SYSTEM) {
362       return true;
363    }
364
365    if (!dcr->WroteVol) {
366       return true;                    /* nothing written to tape */
367    }
368
369    dcr->WroteVol = false;
370    bnet_fsend(dir, Create_job_media, jcr->Job,
371       dcr->VolFirstIndex, dcr->VolLastIndex,
372       dcr->StartFile, dcr->EndFile,
373       dcr->StartBlock, dcr->EndBlock, 
374       dcr->Copy, dcr->Stripe, 
375       edit_uint64(dcr->dev->VolCatInfo.VolMediaId, ed1));
376     Dmsg1(100, ">dird: %s", dir->msg);
377    if (bnet_recv(dir) <= 0) {
378       Dmsg0(190, "create_jobmedia error bnet_recv\n");
379       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
380            bnet_strerror(dir));
381       return false;
382    }
383    Dmsg1(100, "<dir: %s", dir->msg);
384    if (strcmp(dir->msg, OK_create) != 0) {
385       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
386       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
387       return false;
388    }
389    return true;
390 }
391
392
393 /*
394  * Update File Attribute data
395  */
396 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
397 {
398    JCR *jcr = dcr->jcr;
399    BSOCK *dir = jcr->dir_bsock;
400    ser_declare;
401
402 #ifdef NO_ATTRIBUTES_TEST
403    return true;
404 #endif
405
406    dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
407    dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
408                 sizeof(DEV_RECORD) + rec->data_len);
409    ser_begin(dir->msg + dir->msglen, 0);
410    ser_uint32(rec->VolSessionId);
411    ser_uint32(rec->VolSessionTime);
412    ser_int32(rec->FileIndex);
413    ser_int32(rec->Stream);
414    ser_uint32(rec->data_len);
415    ser_bytes(rec->data, rec->data_len);
416    dir->msglen = ser_length(dir->msg);
417    Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
418    return bnet_send(dir);
419 }
420
421
422 /*
423  *   Request the sysop to create an appendable volume
424  *
425  *   Entered with device blocked.
426  *   Leaves with device blocked.
427  *
428  *   Returns: true  on success (operator issues a mount command)
429  *            false on failure
430  *              Note, must create dev->errmsg on error return.
431  *
432  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
433  *      information on suggested volume, but this may not be the
434  *      same as what is actually mounted.
435  *
436  *    When we return with success, the correct tape may or may not
437  *      actually be mounted. The calling routine must read it and
438  *      verify the label.
439  */
440 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
441 {
442    int stat = W_TIMEOUT;
443    DEVICE *dev = dcr->dev;
444    JCR *jcr = dcr->jcr;
445    bool got_vol = false;
446
447    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
448    ASSERT(dev->dev_blocked);
449    for ( ;; ) {
450       if (job_canceled(jcr)) {
451          Mmsg(dev->errmsg,
452               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
453               jcr->Job, dev->print_name());
454          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
455          return false;
456       }
457       P(dev->mutex);
458       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
459       V(dev->mutex);
460       if (got_vol) {
461          return true;
462       } else {
463          if (stat == W_TIMEOUT || stat == W_MOUNT) {
464             Jmsg(jcr, M_MOUNT, 0, _(
465 "Job %s waiting. Cannot find any appendable volumes.\n"
466 "Please use the \"label\"  command to create a new Volume for:\n"
467 "    Storage:      %s\n"
468 "    Media type:   %s\n"
469 "    Pool:         %s\n"),
470                jcr->Job,
471                dev->print_name(),
472                dcr->media_type,
473                dcr->pool_name);
474          }
475       }
476
477       set_jcr_job_status(jcr, JS_WaitMedia);
478       dir_send_job_status(jcr);
479
480       stat = wait_for_sysop(dcr);
481       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
482       if (dev->poll) {
483          Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
484          continue;
485       }
486
487       if (stat == W_TIMEOUT) {
488          if (!double_dev_wait_time(dev)) {
489             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
490                dev->print_name(), jcr->Job);
491             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
492             Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
493             return false;             /* exceeded maximum waits */
494          }
495          continue;
496       }
497       if (stat == W_ERROR) {
498          berrno be;
499          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
500          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
501          return false;
502       }
503       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
504    }
505    set_jcr_job_status(jcr, JS_Running);
506    dir_send_job_status(jcr);
507    Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
508    return true;
509 }
510
511 /*
512  *   Request to mount specific Volume
513  *
514  *   Entered with device blocked and dcr->VolumeName is desired
515  *      volume.
516  *   Leaves with device blocked.
517  *
518  *   Returns: true  on success (operator issues a mount command)
519  *            false on failure
520  *                  Note, must create dev->errmsg on error return.
521  *
522  */
523 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
524 {
525    int stat = W_TIMEOUT;
526    DEVICE *dev = dcr->dev;
527    JCR *jcr = dcr->jcr;
528
529    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
530    if (!dcr->VolumeName[0]) {
531       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
532       return false;
533    }
534    ASSERT(dev->dev_blocked);
535    for ( ;; ) {
536       if (job_canceled(jcr)) {
537          Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
538               jcr->Job, dev->print_name());
539          return false;
540       }
541
542       if (dev->is_dvd()) {   
543          dev->unmount(0);
544       }
545       
546       /*
547        * If we are not polling, and the wait timeout or the
548        *   user explicitly did a mount, send him the message.
549        *   Otherwise skip it.
550        */
551       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
552          Jmsg(jcr, M_MOUNT, 0, _("Please mount Volume \"%s\" on Storage Device %s for Job %s\n"),
553               dcr->VolumeName, dev->print_name(), jcr->Job);
554          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
555                dcr->VolumeName, dev->print_name(), jcr->Job);
556       }
557
558       set_jcr_job_status(jcr, JS_WaitMount);
559       dir_send_job_status(jcr);
560
561       stat = wait_for_sysop(dcr);          /* wait on device */
562       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
563       if (dev->poll) {
564          Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
565          Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
566          return true;
567       }
568
569       if (stat == W_TIMEOUT) {
570          if (!double_dev_wait_time(dev)) {
571             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
572                dev->print_name(), jcr->Job);
573             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
574             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
575             return false;             /* exceeded maximum waits */
576          }
577          continue;
578       }
579       if (stat == W_ERROR) {
580          berrno be;
581          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
582          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
583          return false;
584       }
585       Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
586       break;
587    }
588    set_jcr_job_status(jcr, JS_Running);
589    dir_send_job_status(jcr);
590    Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");
591    return true;
592 }