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