]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/askdir.c
Fix bug 2323 -- loop exit condition was backward and add error message
[bacula/bacula] / bacula / src / stored / askdir.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Subroutines to handle Catalog reqests sent to the Director
21  *   Reqests/commands from the Director are handled in dircmd.c
22  *
23  *   Kern Sibbald, December 2000
24  */
25
26 #include "bacula.h"                   /* pull in global headers */
27 #include "stored.h"                   /* pull in Storage Deamon headers */
28
29 static const int dbglvl = 200;
30
31 /* Requests sent to the Director */
32 static char Find_media[]   = "CatReq JobId=%ld FindMedia=%d pool_name=%s media_type=%s vol_type=%d\n";
33 static char Get_Vol_Info[] = "CatReq JobId=%ld GetVolInfo VolName=%s write=%d\n";
34 static char Update_media[] = "CatReq JobId=%ld UpdateMedia VolName=%s"
35    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolABytes=%s"
36    " VolHoleBytes=%s VolHoles=%u VolMounts=%u"
37    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
38    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
39    " VolFirstWritten=%s VolType=%u VolParts=%d VolCloudParts=%d"
40    " LastPartBytes=%lld Enabled=%d\n";
41 static char Create_jobmedia[] = "CatReq JobId=%ld CreateJobMedia\n";
42 static char FileAttributes[] = "UpdCat JobId=%ld FileAttributes ";
43
44 /* Responses received from the Director */
45 static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
46    " VolBlocks=%lu VolBytes=%lld VolABytes=%lld"
47    " VolHoleBytes=%lld VolHoles=%lu VolMounts=%lu"
48    " VolErrors=%lu VolWrites=%lu"
49    " MaxVolBytes=%lld VolCapacityBytes=%lld VolStatus=%20s"
50    " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
51    " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
52    " VolType=%lu LabelType=%ld MediaId=%lld ScratchPoolId=%lld"
53    " VolParts=%d VolCloudParts=%d LastPartBytes=%lld Enabled=%d\n";
54
55
56 static char OK_create[] = "1000 OK CreateJobMedia\n";
57
58 static bthread_mutex_t vol_info_mutex = BTHREAD_MUTEX_PRIORITY(PRIO_SD_VOL_INFO);
59
60 #ifdef needed
61
62 static char Device_update[] = "DevUpd JobId=%ld device=%s "
63    "append=%d read=%d num_writers=%d "
64    "open=%d labeled=%d offline=%d "
65    "reserved=%d max_writers=%d "
66    "autoselect=%d autochanger=%d "
67    "enabled=%d "
68    "changer_name=%s media_type=%s volume_name=%s\n";
69
70
71 /** Send update information about a device to Director */
72 bool dir_update_device(JCR *jcr, DEVICE *dev)
73 {
74    BSOCK *dir = jcr->dir_bsock;
75    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
76    DEVRES *device = dev->device;
77    bool ok;
78
79    pm_strcpy(dev_name, device->hdr.name);
80    bash_spaces(dev_name);
81    if (dev->is_labeled()) {
82       pm_strcpy(VolumeName, dev->VolHdr.VolumeName);
83    } else {
84       pm_strcpy(VolumeName, "*");
85    }
86    bash_spaces(VolumeName);
87    pm_strcpy(MediaType, device->media_type);
88    bash_spaces(MediaType);
89    if (device->changer_res) {
90       pm_strcpy(ChangerName, device->changer_res->hdr.name);
91       bash_spaces(ChangerName);
92    } else {
93       pm_strcpy(ChangerName, "*");
94    }
95    ok = dir->fsend(Device_update,
96       jcr->JobId,
97       dev_name.c_str(),
98       dev->can_append()!=0,
99       dev->can_read()!=0, dev->num_writers,
100       dev->is_open()!=0, dev->is_labeled()!=0,
101       dev->is_offline()!=0, dev->reserved_device,
102       dev->is_tape()?100000:1,
103       dev->autoselect, 0,
104       dev->enabled,
105       ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
106    Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
107    return ok;
108 }
109
110 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
111 {
112    BSOCK *dir = jcr->dir_bsock;
113    POOL_MEM dev_name, MediaType;
114    DEVRES *device;
115    bool ok;
116
117    pm_strcpy(dev_name, changer->hdr.name);
118    bash_spaces(dev_name);
119    device = (DEVRES *)changer->device->first();
120    pm_strcpy(MediaType, device->media_type);
121    bash_spaces(MediaType);
122    /* This is mostly to indicate that we are here */
123    ok = dir->fsend(Device_update,
124       jcr->JobId,
125       dev_name.c_str(),         /* Changer name */
126       0, 0, 0,                  /* append, read, num_writers */
127       0, 0, 0,                  /* is_open, is_labeled, offline */
128       0, 0,                     /* reserved, max_writers */
129       0,                        /* Autoselect */
130       0,                        /* Enabled */
131       changer->device->size(),  /* Number of devices */
132       "0",                      /* PoolId */
133       "*",                      /* ChangerName */
134       MediaType.c_str(),        /* MediaType */
135       "*");                     /* VolName */
136    Dmsg1(dbglvl, ">dird: %s\n", dir->msg);
137    return ok;
138 }
139 #endif
140
141
142 static AskDirHandler *askdir_handler = NULL; /* must be true when inside a "btools" */
143
144 /*
145  * btools must call this function, to modify behavior of some functions here
146  */
147 AskDirHandler *init_askdir_handler(AskDirHandler *new_askdir_handler)
148 {
149    AskDirHandler *old = askdir_handler;
150    askdir_handler = new_askdir_handler;
151    return old;
152 }
153
154 /*
155  * Alternate function used by btools
156  */
157 bool AskDirHandler::dir_ask_sysop_to_mount_volume(DCR *dcr, bool /*writing*/)
158 {
159    DEVICE *dev = dcr->dev;
160    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
161       dcr->VolumeName, dev->print_name());
162    dev->close(dcr);
163    getchar();
164    return true;
165 }
166
167 bool AskDirHandler::dir_get_volume_info(DCR *dcr, const char *VolumeName, enum get_vol_info_rw  writing)
168 {
169    Dmsg0(100, "Fake dir_get_volume_info\n");
170    dcr->setVolCatName(VolumeName);
171    Dmsg2(500, "Vol=%s VolType=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatType);
172    return 1;
173 }
174
175 /**
176  * Send current JobStatus to Director
177  */
178 bool dir_send_job_status(JCR *jcr)
179 {
180    if (askdir_handler) {
181       return askdir_handler->dir_send_job_status(jcr);
182    }
183
184    return jcr->sendJobStatus();
185 }
186
187 /**
188  * Common routine for:
189  *   dir_get_volume_info()
190  * and
191  *   dir_find_next_appendable_volume()
192  *
193  *  NOTE!!! All calls to this routine must be protected by
194  *          locking vol_info_mutex before calling it so that
195  *          we don't have one thread modifying the parameters
196  *          and another reading them.
197  *
198  *  Returns: true  on success and vol info in dcr->VolCatInfo
199  *           false on failure
200  */
201 static bool do_get_volume_info(DCR *dcr)
202 {
203     JCR *jcr = dcr->jcr;
204     BSOCK *dir = jcr->dir_bsock;
205     VOLUME_CAT_INFO vol;
206     int n;
207     int32_t Enabled;
208     int32_t InChanger;
209
210     dcr->setVolCatInfo(false);
211     if (dir->recv() <= 0) {
212        Dmsg0(dbglvl, "getvolname error bnet_recv\n");
213        Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
214        return false;
215     }
216     memset(&vol, 0, sizeof(vol));
217     n = sscanf(dir->msg, OK_media, vol.VolCatName,
218                &vol.VolCatJobs, &vol.VolCatFiles,
219                &vol.VolCatBlocks, &vol.VolCatAmetaBytes,
220                &vol.VolCatAdataBytes, &vol.VolCatHoleBytes,
221                &vol.VolCatHoles, &vol.VolCatMounts, &vol.VolCatErrors,
222                &vol.VolCatWrites, &vol.VolCatMaxBytes,
223                &vol.VolCatCapacityBytes, vol.VolCatStatus,
224                &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles,
225                &InChanger, &vol.VolReadTime, &vol.VolWriteTime,
226                &vol.EndFile, &vol.EndBlock, &vol.VolCatType,
227                &vol.LabelType, &vol.VolMediaId, &vol.VolScratchPoolId,
228                &vol.VolCatParts, &vol.VolCatCloudParts,
229                &vol.VolLastPartBytes, &Enabled);
230     Dmsg2(dbglvl, "<dird n=%d %s", n, dir->msg);
231     if (n != 30) {
232        Dmsg1(dbglvl, "get_volume_info failed: ERR=%s", dir->msg);
233        /*
234         * Note, we can get an error here either because there is
235         *  a comm problem, or if the volume is not a suitable
236         *  volume to use, so do not issue a Jmsg() here, do it
237         *  in the calling routine.
238         */
239        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
240        return false;
241     }
242     vol.InChanger = InChanger;        /* bool in structure */
243     vol.VolEnabled = Enabled;         /* bool in structure */
244     vol.is_valid = true;
245     vol.VolCatBytes = vol.VolCatAmetaBytes + vol.VolCatAdataBytes;
246     unbash_spaces(vol.VolCatName);
247     bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
248     dcr->VolCatInfo = vol;            /* structure assignment */
249
250     Dmsg3(dbglvl, "do_reqest_vol_info return true slot=%d Volume=%s MediaId=%lld\n",
251           dcr->VolCatInfo.Slot, dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolMediaId);
252     Dmsg5(dbglvl, "Dir returned VolCatAmetaBytes=%lld VolCatAdataBytes=%lld Status=%s Vol=%s MediaId=%lld\n",
253        dcr->VolCatInfo.VolCatAmetaBytes, dcr->VolCatInfo.VolCatAdataBytes,
254        dcr->VolCatInfo.VolCatStatus, dcr->VolCatInfo.VolCatName,
255        dcr->VolCatInfo.VolMediaId);
256     return true;
257 }
258
259
260 /**
261  * Get Volume info for a specific volume from the Director's Database
262  *
263  * Returns: true  on success   (Director guarantees that Pool and MediaType
264  *                              are correct and VolStatus==Append or
265  *                              VolStatus==Recycle)
266  *          false on failure
267  *
268  *          Volume information returned in dcr->VolCatInfo
269  */
270 bool dir_get_volume_info(DCR *dcr,
271                          const char *VolumeName,
272                          enum get_vol_info_rw writing)
273 {
274    if (askdir_handler) {
275       return askdir_handler->dir_get_volume_info(dcr, VolumeName, writing);
276    }
277
278    JCR *jcr = dcr->jcr;
279    BSOCK *dir = jcr->dir_bsock;
280
281    P(vol_info_mutex);
282    dcr->setVolCatName(VolumeName);
283    bash_spaces(dcr->getVolCatName());
284    dir->fsend(Get_Vol_Info, jcr->JobId, dcr->getVolCatName(),
285       writing==GET_VOL_INFO_FOR_WRITE?1:0);
286    Dmsg1(dbglvl, ">dird %s", dir->msg);
287    unbash_spaces(dcr->getVolCatName());
288    bool ok = do_get_volume_info(dcr);
289    V(vol_info_mutex);
290    return ok;
291 }
292
293
294
295 /**
296  * Get info on the next appendable volume in the Director's database
297  *
298  * Returns: true  on success dcr->VolumeName is volume
299  *                reserve_volume() called on Volume name
300  *          false on failure dcr->VolumeName[0] == 0
301  *                also sets dcr->found_in_use if at least one
302  *                in use volume was found.
303  *
304  *          Volume information returned in dcr
305  *
306  */
307 bool dir_find_next_appendable_volume(DCR *dcr)
308 {
309     /* SD tools setup a handler because they have no connection to Dir */
310     if (askdir_handler) {
311        return askdir_handler->dir_find_next_appendable_volume(dcr);
312     }
313
314     JCR *jcr = dcr->jcr;
315     BSOCK *dir = jcr->dir_bsock;
316     bool rtn;
317     char lastVolume[MAX_NAME_LENGTH];
318
319     Dmsg2(dbglvl, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n",
320        dcr->is_reserved(), dcr->VolumeName);
321     Mmsg(jcr->errmsg, "Unknown error\n");
322
323     /*
324      * Try the thirty oldest or most available volumes.  Note,
325      *   the most available could already be mounted on another
326      *   drive, so we continue looking for a not in use Volume.
327      */
328     lock_volumes();
329     P(vol_info_mutex);
330     dcr->clear_found_in_use();
331     lastVolume[0] = 0;
332     for (int vol_index=1;  vol_index < 30; vol_index++) {
333        bash_spaces(dcr->media_type);
334        bash_spaces(dcr->pool_name);
335        dir->fsend(Find_media, jcr->JobId, vol_index, dcr->pool_name, dcr->media_type,
336                   dcr->dev->dev_type);
337        unbash_spaces(dcr->media_type);
338        unbash_spaces(dcr->pool_name);
339        Dmsg1(dbglvl, ">dird %s", dir->msg);
340        if (do_get_volume_info(dcr)) {
341           /* Give up if we get the same volume name twice */
342           if (lastVolume[0] && strcmp(lastVolume, dcr->VolumeName) == 0) {
343              Mmsg(jcr->errmsg, "Director returned same volume name=%s twice.\n",
344                 lastVolume);
345              Dmsg1(dbglvl, "Got same vol = %s\n", lastVolume);
346              break;
347           }
348           /* If VolCatAdataBytes, we have ALIGNED_DEV */
349           if (dcr->VolCatInfo.VolCatType == 0 && dcr->VolCatInfo.VolCatAdataBytes != 0) {
350              dcr->VolCatInfo.VolCatType = B_ALIGNED_DEV;
351           }
352           /*
353            * If we have VolType and we are disk or aligned, the VolType must match
354            */
355           /* ***FIXME*** find better way to handle voltype */
356           if (dcr->VolCatInfo.VolCatType != 0 &&
357               (dcr->dev->dev_type == B_FILE_DEV || dcr->dev->dev_type == B_ALIGNED_DEV || 
358                dcr->dev->dev_type == B_CLOUD_DEV) &&
359                dcr->dev->dev_type != (int)dcr->VolCatInfo.VolCatType) {
360              Dmsg2(000, "Skip vol. Wanted VolType=%d Got=%d\n", dcr->dev->dev_type, dcr->VolCatInfo.VolCatType);
361              continue;
362           }
363           bstrncpy(lastVolume, dcr->VolumeName, sizeof(lastVolume));
364           if (dcr->can_i_write_volume()) {
365              Dmsg1(dbglvl, "Call reserve_volume for write. Vol=%s\n", dcr->VolumeName);
366              if (reserve_volume(dcr, dcr->VolumeName) == NULL) {
367                 Dmsg1(dbglvl, "%s", jcr->errmsg);
368                 if (dcr->dev->must_wait()) {
369                    rtn = false;
370                    dcr->VolumeName[0] = 0;
371                    goto get_out;
372                 }
373                 continue;
374              }
375              Dmsg1(dbglvl, "dir_find_next_appendable_volume return true. vol=%s\n",
376                 dcr->VolumeName);
377              rtn = true;
378              goto get_out;
379           } else {
380              Mmsg(jcr->errmsg, "Volume %s is in use.\n", dcr->VolumeName);
381              Dmsg1(dbglvl, "Volume %s is in use.\n", dcr->VolumeName);
382              /* If volume is not usable, it is in use by someone else */
383              dcr->set_found_in_use();
384              continue;
385           }
386        }
387        Dmsg2(dbglvl, "No vol. index %d return false. dev=%s\n", vol_index,
388           dcr->dev->print_name());
389        break;
390     }
391     rtn = false;
392     dcr->VolumeName[0] = 0;
393
394 get_out:
395     V(vol_info_mutex);
396     unlock_volumes();
397     if (!rtn && dcr->VolCatInfo.VolScratchPoolId != 0) {
398        Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
399        Dmsg2(000, "!!!!!!!!! Volume=%s rejected ScratchPoolId=%lld\n", dcr->VolumeName,
400           dcr->VolCatInfo.VolScratchPoolId);
401        Dmsg1(000, "%s", jcr->errmsg);
402     //} else {
403     //   Dmsg3(000, "Rtn=%d Volume=%s ScratchPoolId=%lld\n", rtn, dcr->VolumeName,
404     //      dcr->VolCatInfo.VolScratchPoolId);
405     }
406     return rtn;
407 }
408
409
410 /*
411  * After writing a Volume, send the updated statistics
412  * back to the director. The information comes from the
413  * dev record.
414  */
415 bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten,
416                             bool use_dcr)
417 {
418    if (askdir_handler) {
419       return askdir_handler->dir_update_volume_info(dcr, label, update_LastWritten, use_dcr);
420    }
421
422    JCR *jcr = dcr->jcr;
423    BSOCK *dir = jcr->dir_bsock;
424    DEVICE *dev = dcr->ameta_dev;
425    VOLUME_CAT_INFO vol;
426    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
427    int InChanger;
428    bool ok = false;
429    POOL_MEM VolumeName;
430
431    /* If system job, do not update catalog, except if we explicitly force it. */
432    if (jcr->getJobType() == JT_SYSTEM && 
433        !dcr->force_update_volume_info) {
434       return true;
435    }
436
437    /* Lock during Volume update */
438    P(vol_info_mutex);
439    dev->Lock_VolCatInfo();
440
441    if (use_dcr) {
442       vol = dcr->VolCatInfo;        /* structure assignment */
443    } else {
444       vol = dev->VolCatInfo;        /* structure assignment */
445    }
446
447    /* This happens when nothing to update after fixup_device ... */
448    if (vol.VolCatName[0] == 0) {
449       goto bail_out;
450    }
451    Dmsg4(100, "Update cat VolBytes=%lld VolABytes=%lld Status=%s Vol=%s\n",
452       vol.VolCatAmetaBytes, vol.VolCatAdataBytes, vol.VolCatStatus, vol.VolCatName);
453    /* Just labeled or relabeled the tape */
454    if (label) {
455       dev->setVolCatStatus("Append");
456    }
457 // if (update_LastWritten) {
458       vol.VolLastWritten = time(NULL);
459 // }
460    pm_strcpy(VolumeName, vol.VolCatName);
461    bash_spaces(VolumeName);
462    InChanger = vol.InChanger;
463    /* Insanity test */
464    if (vol.VolCatHoleBytes > (((uint64_t)2)<<60)) {
465       Pmsg1(010, "VolCatHoleBytes too big: %lld. Reset to zero.\n",
466          vol.VolCatHoleBytes);
467       vol.VolCatHoleBytes = 0;
468    }
469    /* Set device type where this Volume used */
470    if (vol.VolCatType == 0) {
471       vol.VolCatType = dev->dev_type;
472    }
473    dir->fsend(Update_media, jcr->JobId,
474       VolumeName.c_str(), vol.VolCatJobs, vol.VolCatFiles,
475       vol.VolCatBlocks, edit_uint64(vol.VolCatAmetaBytes, ed1),
476       edit_uint64(vol.VolCatAdataBytes, ed2),
477       edit_uint64(vol.VolCatHoleBytes, ed3),
478       vol.VolCatHoles, vol.VolCatMounts, vol.VolCatErrors,
479       vol.VolCatWrites, edit_uint64(vol.VolCatMaxBytes, ed4),
480       edit_uint64(vol.VolLastWritten, ed5),
481       vol.VolCatStatus, vol.Slot, label,
482       InChanger,                      /* bool in structure */
483       edit_int64(vol.VolReadTime, ed6),
484       edit_int64(vol.VolWriteTime, ed7),
485       edit_uint64(vol.VolFirstWritten, ed8),
486       vol.VolCatType,
487       vol.VolCatParts,
488       vol.VolCatCloudParts,
489       vol.VolLastPartBytes,
490       vol.VolEnabled);
491     Dmsg1(100, ">dird %s", dir->msg);
492
493    /* Do not lock device here because it may be locked from label */
494    if (!jcr->is_canceled()) {
495       /*
496        * We sent info directly from dev to the Director.
497        *  What the Director sends back is first read into
498        *  the dcr with do_get_volume_info()
499        */
500       if (!do_get_volume_info(dcr)) {
501          Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
502          Dmsg2(dbglvl, _("Didn't get vol info vol=%s: ERR=%s"),
503             vol.VolCatName, jcr->errmsg);
504          goto bail_out;
505       }
506       Dmsg1(100, "get_volume_info() %s", dir->msg);
507
508       /* Update dev Volume info in case something changed (e.g. expired) */
509       if (!use_dcr) {
510          dcr->VolCatInfo.Slot = dev->VolCatInfo.Slot;
511          bstrncpy(dcr->VolCatInfo.VolCatStatus, dev->VolCatInfo.VolCatStatus, sizeof(vol.VolCatStatus));
512          dcr->VolCatInfo.VolCatAdataBytes = dev->VolCatInfo.VolCatAdataBytes;
513          dcr->VolCatInfo.VolCatAmetaBytes = dev->VolCatInfo.VolCatAmetaBytes;
514          dcr->VolCatInfo.VolCatHoleBytes = dev->VolCatInfo.VolCatHoleBytes;
515          dcr->VolCatInfo.VolCatHoles = dev->VolCatInfo.VolCatHoles;
516          dcr->VolCatInfo.VolCatPadding = dev->VolCatInfo.VolCatPadding;
517          dcr->VolCatInfo.VolCatAmetaPadding = dev->VolCatInfo.VolCatAmetaPadding;
518          dcr->VolCatInfo.VolCatAdataPadding = dev->VolCatInfo.VolCatAdataPadding;
519          dcr->VolCatInfo.VolCatFiles = dev->VolCatInfo.VolCatFiles;
520          dcr->VolCatInfo.VolCatBytes = dev->VolCatInfo.VolCatBytes;
521          dcr->VolCatInfo.VolCatMounts = dev->VolCatInfo.VolCatMounts;
522          dcr->VolCatInfo.VolCatJobs = dev->VolCatInfo.VolCatJobs;
523          dcr->VolCatInfo.VolCatFiles = dev->VolCatInfo.VolCatFiles;
524          dcr->VolCatInfo.VolCatRecycles = dev->VolCatInfo.VolCatRecycles;
525          dcr->VolCatInfo.VolCatWrites = dev->VolCatInfo.VolCatWrites;
526          dcr->VolCatInfo.VolCatReads = dev->VolCatInfo.VolCatReads;
527       }
528       ok = true;
529    }
530
531 bail_out:
532    dev->Unlock_VolCatInfo();
533    V(vol_info_mutex);
534    return ok;
535 }
536
537 struct JOBMEDIA_ITEM {
538    dlink link;
539    int64_t  VolMediaId;
540    uint64_t StartAddr;
541    uint64_t EndAddr;
542    uint32_t VolFirstIndex;
543    uint32_t VolLastIndex;
544    uint32_t StartFile;
545    uint32_t EndFile;
546    uint32_t StartBlock;
547    uint32_t EndBlock;
548 };
549
550 void create_jobmedia_queue(JCR *jcr)
551 {
552    JOBMEDIA_ITEM *item = NULL;
553    jcr->jobmedia_queue = New(dlist(item, &item->link));
554 }
555
556 bool flush_jobmedia_queue(JCR *jcr)
557 {
558    if (askdir_handler) {
559       return askdir_handler->flush_jobmedia_queue(jcr);
560    }
561
562    JOBMEDIA_ITEM *item;
563    BSOCK *dir = jcr->dir_bsock;
564    bool ok;
565
566    if (!jcr->jobmedia_queue || jcr->jobmedia_queue->size() == 0) {
567       return true;     /* should never happen */
568    }
569    Dmsg1(400, "=== Flush jobmedia queue = %d\n", jcr->jobmedia_queue->size());
570
571    dir->fsend(Create_jobmedia, jcr->JobId);
572    foreach_dlist(item, jcr->jobmedia_queue) {
573       ok = dir->fsend("%u %u %u %u %u %u %lld\n",
574          item->VolFirstIndex, item->VolLastIndex,
575          item->StartFile, item->EndFile,
576          item->StartBlock, item->EndBlock,
577          item->VolMediaId);
578       Dmsg2(400, "sd->dir: ok=%d Jobmedia=%s", ok, dir->msg);
579    }
580    dir->signal(BNET_EOD);
581    jcr->jobmedia_queue->destroy();
582
583    if (dir->recv() <= 0) {
584       Dmsg0(dbglvl, "create_jobmedia error bnet_recv\n");
585       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia records: ERR=%s\n"),
586            dir->bstrerror());
587       return false;
588    }
589    Dmsg1(210, "<dird %s", dir->msg);
590    if (strcmp(dir->msg, OK_create) != 0) {
591       Dmsg1(dbglvl, "Bad response from Dir: %s\n", dir->msg);
592       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia records: %s\n"), dir->msg);
593       return false;
594    }
595    return true;
596 }
597
598
599 /*
600  * After writing a Volume, create the JobMedia record.
601  */
602 bool dir_create_jobmedia_record(DCR *dcr, bool zero)
603 {
604    if (askdir_handler) {
605       return askdir_handler->dir_create_jobmedia_record(dcr, zero);
606    }
607
608    JCR *jcr = dcr->jcr;
609    BSOCK *dir = jcr->dir_bsock;
610    JOBMEDIA_ITEM *item;
611    bool ok = true;;
612
613    if (!zero && !dcr->WroteVol) {
614       return true;
615    }
616    if (!zero && dcr->VolLastIndex == 0) {
617       Pmsg7(0/*dbglvl*/, "Discard: JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
618          dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
619          dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
620       return true;                    /* nothing written to the Volume */
621    }
622    /* Throw out records where the start address is bigger than the end */
623    if (!zero && dcr->StartAddr > dcr->EndAddr) {
624       Pmsg7(0/*dbglvl*/, "Discard: JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
625          dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
626          dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
627       return true;
628    }
629
630    /* If system job, do not update catalog */
631    if (jcr->getJobType() == JT_SYSTEM) {
632       return true;
633    }
634
635    /* Throw out records where FI is zero -- i.e. nothing done */
636    if (!zero && dcr->VolFirstIndex == 0 &&
637         (dcr->StartAddr != 0 || dcr->EndAddr != 0)) {
638       Pmsg7(0/*dbglvl*/, "Discard: JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
639          dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
640          dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
641       return true;
642    }
643
644    /*
645     * If this Job is incomplete, we need to backup the FileIndex
646     *  to the last correctly saved file so that the JobMedia
647     *  LastIndex is correct.
648     *
649     *  Note: ***FIXME*** though it is not required, we probably
650     *   should also keep a last EndFile and last EndBlock and
651     *   reset them correctly too so that the JobMedia record is
652     *   really correct.
653     */
654    if (jcr->is_JobStatus(JS_Incomplete)) {
655       dcr->VolLastIndex = dir->get_lastFileIndex();
656       Dmsg1(100, "======= Set FI=%ld\n", dcr->VolLastIndex);
657    }
658
659    Dmsg7(100, "Queue JobMedia Vol=%s wrote=%d MediaId=%lld FI=%lu LI=%lu StartAddr=%lld EndAddr=%lld\n",
660       dcr->VolumeName, dcr->WroteVol, dcr->VolMediaId,
661       dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartAddr, dcr->EndAddr);
662    item = (JOBMEDIA_ITEM *)malloc(sizeof(JOBMEDIA_ITEM));
663    if (zero) {
664       item->VolFirstIndex = item->VolLastIndex = 0;
665       item->StartFile = item->EndFile = 0;
666       item->StartBlock = item->EndBlock = 0;
667       item->StartAddr = item->EndAddr = 0;
668       item->VolMediaId = dcr->VolMediaId;
669    } else {
670       item->VolFirstIndex = dcr->VolFirstIndex;
671       item->VolLastIndex = dcr->VolLastIndex;
672       item->StartFile = (uint32_t)(dcr->StartAddr >> 32);
673       item->EndFile = (uint32_t)(dcr->EndAddr >> 32);
674       item->StartBlock = (uint32_t)dcr->StartAddr;
675       item->EndBlock = (uint32_t)dcr->EndAddr;
676       item->StartAddr = dcr->StartAddr;
677       item->EndAddr = dcr->EndAddr;
678       item->VolMediaId = dcr->VolMediaId;
679    }
680    jcr->jobmedia_queue->append(item);
681    /* Flush at 100 queue size of 100 jobmedia records */
682    if (zero || jcr->jobmedia_queue->size() >= 100) {
683       ok = flush_jobmedia_queue(jcr);
684    }
685
686    dcr->VolFirstIndex = dcr->VolLastIndex = 0;
687    dcr->StartAddr = dcr->EndAddr = 0;
688    dcr->VolMediaId = 0;
689    dcr->WroteVol = false;
690    return ok;
691 }
692
693 /*
694  * Update File Attribute data
695  * We do the following:
696  *  1. expand the bsock buffer to be large enough
697  *  2. Write a "header" into the buffer with serialized data
698  *    VolSessionId
699  *    VolSeesionTime
700  *    FileIndex
701  *    Stream
702  *    data length that follows
703  *    start of raw byte data from the Device record.
704  * Note, this is primarily for Attribute data, but can
705  *   also handle any device record. The Director must know
706  *   the raw byte data format that is defined for each Stream.
707  * Now Restore Objects pass through here STREAM_RESTORE_OBJECT
708  */
709 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
710 {
711    if (askdir_handler) {
712       return askdir_handler->dir_update_file_attributes(dcr, rec);
713    }
714
715    JCR *jcr = dcr->jcr;
716    BSOCK *dir = jcr->dir_bsock;
717    ser_declare;
718
719 #ifdef NO_ATTRIBUTES_TEST
720    return true;
721 #endif
722
723    dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
724                 MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
725    dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
726                 MAX_NAME_LENGTH + 1, FileAttributes, jcr->JobId);
727    ser_begin(dir->msg + dir->msglen, 0);
728    ser_uint32(rec->VolSessionId);
729    ser_uint32(rec->VolSessionTime);
730    ser_int32(rec->FileIndex);
731    ser_int32(rec->Stream);
732    ser_uint32(rec->data_len);
733    ser_bytes(rec->data, rec->data_len);
734    dir->msglen = ser_length(dir->msg);
735    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
736    if (rec->maskedStream == STREAM_UNIX_ATTRIBUTES ||
737        rec->maskedStream == STREAM_UNIX_ATTRIBUTES_EX) {
738       Dmsg2(1500, "==== set_data_end FI=%ld %s\n", rec->FileIndex, rec->data);
739       dir->set_data_end(rec->FileIndex);    /* set offset of valid data */
740    }
741    return dir->send();
742 }
743
744
745 /**
746  *   Request the sysop to create an appendable volume
747  *
748  *   Entered with device blocked.
749  *   Leaves with device blocked.
750  *
751  *   Returns: true  on success (operator issues a mount command)
752  *            false on failure
753  *              Note, must create dev->errmsg on error return.
754  *
755  *    On success, dcr->VolumeName and dcr->VolCatInfo contain
756  *      information on suggested volume, but this may not be the
757  *      same as what is actually mounted.
758  *
759  *    When we return with success, the correct tape may or may not
760  *      actually be mounted. The calling routine must read it and
761  *      verify the label.
762  */
763 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
764 {
765    if (askdir_handler) {
766       return askdir_handler->dir_ask_sysop_to_create_appendable_volume(dcr);
767    }
768
769    int stat = W_TIMEOUT;
770    DEVICE *dev = dcr->dev;
771    JCR *jcr = dcr->jcr;
772    bool got_vol = false;
773
774    if (job_canceled(jcr)) {
775       dev->poll = false;
776       return false;
777    }
778    Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
779    ASSERT(dev->blocked());
780    for ( ;; ) {
781       if (job_canceled(jcr)) {
782          Mmsg(dev->errmsg,
783               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
784               jcr->Job, dev->print_name());
785          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
786          dev->poll = false;
787          return false;
788       }
789       got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
790       if (got_vol) {
791          goto get_out;
792       } else {
793          dev->clear_wait();
794          if (stat == W_TIMEOUT || stat == W_MOUNT) {
795             Mmsg(dev->errmsg, _(
796 "Job %s is waiting. Cannot find any appendable volumes.\n"
797 "Please use the \"label\" command to create a new Volume for:\n"
798 "    Storage:      %s\n"
799 "    Pool:         %s\n"
800 "    Media type:   %s\n"),
801                jcr->Job,
802                dev->print_name(),
803                dcr->pool_name,
804                dcr->media_type);
805             Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
806             Dmsg1(dbglvl, "%s", dev->errmsg);
807          }
808       }
809
810       jcr->sendJobStatus(JS_WaitMedia);
811
812       stat = wait_for_sysop(dcr);
813       Dmsg1(dbglvl, "Back from wait_for_sysop stat=%d\n", stat);
814       if (dev->poll) {
815          Dmsg1(dbglvl, "Poll timeout in create append vol on device %s\n", dev->print_name());
816          continue;
817       }
818
819       if (stat == W_TIMEOUT) {
820          if (!double_dev_wait_time(dev)) {
821             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
822                dev->print_name(), jcr->Job);
823             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
824             Dmsg1(dbglvl, "Gave up waiting on device %s\n", dev->print_name());
825             dev->poll = false;
826             return false;             /* exceeded maximum waits */
827          }
828          continue;
829       }
830       if (stat == W_ERROR) {
831          berrno be;
832          Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
833          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
834          dev->poll = false;
835          return false;
836       }
837       Dmsg1(dbglvl, "Someone woke me for device %s\n", dev->print_name());
838    }
839
840 get_out:
841    jcr->sendJobStatus(JS_Running);
842    Dmsg0(dbglvl, "leave dir_ask_sysop_to_create_appendable_volume\n");
843    return true;
844 }
845
846 /*
847  *   Request to mount specific Volume
848  *
849  *   Entered with device blocked and dcr->VolumeName is desired
850  *      volume.
851  *   Leaves with device blocked.
852  *
853  *   Returns: true  on success (operator issues a mount command)
854  *            false on failure
855  *                  Note, must create dev->errmsg on error return.
856  *
857  */
858 bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool write_access)
859 {
860    if (askdir_handler) {
861       return askdir_handler->dir_ask_sysop_to_mount_volume(dcr, write_access);
862    }
863
864    int stat = W_TIMEOUT;
865    DEVICE *dev = dcr->dev;
866    JCR *jcr = dcr->jcr;
867
868    Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
869    if (!dcr->VolumeName[0]) {
870       Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
871       dev->poll = false;
872       return false;
873    }
874
875    if (dcr->no_mount_request) {
876       Mmsg(dev->errmsg, _("The current operation doesn't support mount request\n"));
877       dev->poll = false;
878       return false;
879    }
880
881    for ( ;; ) {
882       if (job_canceled(jcr)) {
883          Mmsg(dev->errmsg,
884               _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
885               jcr->Job, dev->print_name());
886          Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
887          dev->poll = false;
888          return false;
889       }
890       /*
891        * If we are not polling, and the wait timeout or the
892        *   user explicitly did a mount, send him the message.
893        *   Otherwise skip it.
894        */
895       if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
896          const char *msg;
897          if (write_access) {
898             msg = _("%sPlease mount append Volume \"%s\" or label a new one for:\n"
899               "    Job:          %s\n"
900               "    Storage:      %s\n"
901               "    Pool:         %s\n"
902               "    Media type:   %s\n");
903          } else {
904             msg = _("%sPlease mount read Volume \"%s\" for:\n"
905               "    Job:          %s\n"
906               "    Storage:      %s\n"
907               "    Pool:         %s\n"
908               "    Media type:   %s\n");
909          }
910          Jmsg(jcr, M_MOUNT, 0, msg,
911               dev->is_nospace()?_("\n\nWARNING: device is full! Please add more disk space then ...\n\n"):"",
912               dcr->VolumeName,
913               jcr->Job,
914               dev->print_name(),
915               dcr->pool_name,
916               dcr->media_type);
917          Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
918                dcr->VolumeName, dev->print_name(), jcr->Job);
919       }
920
921       jcr->sendJobStatus(JS_WaitMount);
922
923       stat = wait_for_sysop(dcr);          /* wait on device */
924       Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
925       if (dev->poll) {
926          Dmsg1(100, "Poll timeout in mount vol on device %s\n", dev->print_name());
927          Dmsg1(100, "Blocked=%s\n", dev->print_blocked());
928          goto get_out;
929       }
930
931       if (stat == W_TIMEOUT) {
932          if (!double_dev_wait_time(dev)) {
933             Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
934                dev->print_name(), jcr->Job);
935             Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
936             Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
937             dev->poll = false;
938             return false;             /* exceeded maximum waits */
939          }
940          continue;
941       }
942       if (stat == W_ERROR) {
943          berrno be;
944          Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
945          Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
946          dev->poll = false;
947          return false;
948       }
949       Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
950       break;
951    }
952
953 get_out:
954    if (job_canceled(jcr)) {
955       Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
956            jcr->Job, dev->print_name());
957       dev->poll = false;
958       return false;
959    }
960
961    jcr->sendJobStatus(JS_Running);
962    Dmsg0(100, "leave dir_ask_sysop_to_mount_volume\n");
963    return true;
964 }