2 * Subroutines to handle Catalog reqests sent to the Director
3 * Reqests/commands from the Director are handled in dircmd.c
5 * Kern Sibbald, December 2000
10 Copyright (C) 2000-2006 Kern Sibbald
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.
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.
24 #include "bacula.h" /* pull in global headers */
25 #include "stored.h" /* pull in Storage Deamon headers */
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"
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";
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";
52 static char OK_create[] = "1000 OK CreateJobMedia\n";
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";
64 /* Send update information about a device to Director */
65 bool dir_update_device(JCR *jcr, DEVICE *dev)
67 BSOCK *dir = jcr->dir_bsock;
68 POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
69 DEVRES *device = dev->device;
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);
77 pm_strcpy(VolumeName, "*");
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);
86 pm_strcpy(ChangerName, "*");
88 ok =bnet_fsend(dir, Device_update,
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,
97 ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str());
98 Dmsg1(100, ">dird: %s\n", dir->msg);
102 bool dir_update_changer(JCR *jcr, AUTOCHANGER *changer)
104 BSOCK *dir = jcr->dir_bsock;
105 POOL_MEM dev_name, MediaType;
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,
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 */
122 changer->device->size(), /* Number of devices */
124 "*", /* ChangerName */
125 MediaType.c_str(), /* MediaType */
127 Dmsg1(100, ">dird: %s\n", dir->msg);
134 * Send current JobStatus to Director
136 bool dir_send_job_status(JCR *jcr)
138 return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
142 * Common routine for:
143 * dir_get_volume_info()
145 * dir_find_next_appendable_volume()
147 * Returns: true on success and vol info in dcr->VolCatInfo
150 static bool do_get_volume_info(DCR *dcr)
153 BSOCK *dir = jcr->dir_bsock;
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"));
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,
177 Dmsg2(110, "Bad response from Dir fields=%d: %s", n, dir->msg);
178 Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
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));
186 Dmsg2(300, "do_reqest_vol_info return true slot=%d Volume=%s\n",
187 vol.Slot, vol.VolCatName);
193 * Get Volume info for a specific volume from the Director's Database
195 * Returns: true on success (Director guarantees that Pool and MediaType
196 * are correct and VolStatus==Append or
197 * VolStatus==Recycle)
200 * Volume information returned in dcr->VolCatInfo
202 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing)
205 BSOCK *dir = jcr->dir_bsock;
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);
219 * Get info on the next appendable volume in the Director's database
220 * Returns: true on success
223 * Volume information returned in dcr
226 bool dir_find_next_appendable_volume(DCR *dcr)
229 BSOCK *dir = jcr->dir_bsock;
232 Dmsg0(200, "dir_find_next_appendable_volume\n");
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.
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);
248 if (dcr->any_volume || !is_volume_in_use(dcr)) {
252 Dmsg1(100, "Volume %s is in use.\n", dcr->VolumeName);
256 Dmsg2(100, "No vol. index %d return false. dev=%s\n", vol_index,
257 dcr->dev->print_name());
263 Dmsg0(400, "dir_find_next_appendable_volume return true\n");
264 new_volume(dcr, dcr->VolumeName); /* reserve volume */
265 unlock_reservations();
268 dcr->VolumeName[0] = 0;
269 unlock_reservations();
275 * After writing a Volume, send the updated statistics
276 * back to the director. The information comes from the
279 bool dir_update_volume_info(DCR *dcr, bool label)
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];
286 VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
290 /* If system job, do not update catalog */
291 if (jcr->JobType == JT_SYSTEM) {
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"));
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"));
306 Dmsg1(100, "Update cat VolFiles=%d\n", dev->file);
307 /* Just labeled or relabeled the tape */
309 bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
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),
324 Dmsg1(100, ">dird: %s", dir->msg);
326 /* Do not lock device here because it may be locked from label */
327 if (!do_get_volume_info(dcr)) {
328 Jmsg(jcr, M_FATAL, 0, "%s", jcr->errmsg);
329 Dmsg2(100, _("Didn't get vol info vol=%s: ERR=%s"),
330 vol->VolCatName, jcr->errmsg);
333 Dmsg1(420, "get_volume_info(): %s", dir->msg);
334 /* Update dev Volume info in case something changed (e.g. expired) */
335 memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
340 * After writing a Volume, create the JobMedia record.
342 bool dir_create_jobmedia_record(DCR *dcr)
345 BSOCK *dir = jcr->dir_bsock;
347 /* If system job, do not update catalog */
348 if (jcr->JobType == JT_SYSTEM) {
352 if (!dcr->WroteVol) {
353 return true; /* nothing written to tape */
356 dcr->WroteVol = false;
357 bnet_fsend(dir, Create_job_media, jcr->Job,
358 dcr->VolFirstIndex, dcr->VolLastIndex,
359 dcr->StartFile, dcr->EndFile,
360 dcr->StartBlock, dcr->EndBlock,
361 dcr->Copy, dcr->Stripe);
362 Dmsg1(100, ">dird: %s", dir->msg);
363 if (bnet_recv(dir) <= 0) {
364 Dmsg0(190, "create_jobmedia error bnet_recv\n");
365 Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
369 Dmsg1(100, "<dir: %s", dir->msg);
370 if (strcmp(dir->msg, OK_create) != 0) {
371 Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
372 Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
380 * Update File Attribute data
382 bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
385 BSOCK *dir = jcr->dir_bsock;
388 #ifdef NO_ATTRIBUTES_TEST
392 dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
393 dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
394 sizeof(DEV_RECORD) + rec->data_len);
395 ser_begin(dir->msg + dir->msglen, 0);
396 ser_uint32(rec->VolSessionId);
397 ser_uint32(rec->VolSessionTime);
398 ser_int32(rec->FileIndex);
399 ser_int32(rec->Stream);
400 ser_uint32(rec->data_len);
401 ser_bytes(rec->data, rec->data_len);
402 dir->msglen = ser_length(dir->msg);
403 Dmsg1(1800, ">dird: %s\n", dir->msg); /* Attributes */
404 return bnet_send(dir);
409 * Request the sysop to create an appendable volume
411 * Entered with device blocked.
412 * Leaves with device blocked.
414 * Returns: true on success (operator issues a mount command)
416 * Note, must create dev->errmsg on error return.
418 * On success, dcr->VolumeName and dcr->VolCatInfo contain
419 * information on suggested volume, but this may not be the
420 * same as what is actually mounted.
422 * When we return with success, the correct tape may or may not
423 * actually be mounted. The calling routine must read it and
426 bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
428 int stat = W_TIMEOUT;
429 DEVICE *dev = dcr->dev;
431 bool got_vol = false;
433 Dmsg0(400, "enter dir_ask_sysop_to_create_appendable_volume\n");
434 ASSERT(dev->dev_blocked);
436 if (job_canceled(jcr)) {
438 _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
439 jcr->Job, dev->print_name());
440 Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
444 got_vol = dir_find_next_appendable_volume(dcr); /* get suggested volume */
449 if (stat == W_TIMEOUT || stat == W_MOUNT) {
450 Jmsg(jcr, M_MOUNT, 0, _(
451 "Job %s waiting. Cannot find any appendable volumes.\n"
452 "Please use the \"label\" command to create a new Volume for:\n"
463 set_jcr_job_status(jcr, JS_WaitMedia);
464 dir_send_job_status(jcr);
466 stat = wait_for_sysop(dcr);
467 Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
469 Dmsg1(100, "Poll timeout in create append vol on device %s\n", dev->print_name());
473 if (stat == W_TIMEOUT) {
474 if (!double_dev_wait_time(dev)) {
475 Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
476 dev->print_name(), jcr->Job);
477 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
478 Dmsg1(100, "Gave up waiting on device %s\n", dev->print_name());
479 return false; /* exceeded maximum waits */
483 if (stat == W_ERROR) {
485 Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
486 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
489 Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
491 set_jcr_job_status(jcr, JS_Running);
492 dir_send_job_status(jcr);
493 Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
498 * Request to mount specific Volume
500 * Entered with device blocked and dcr->VolumeName is desired
502 * Leaves with device blocked.
504 * Returns: true on success (operator issues a mount command)
506 * Note, must create dev->errmsg on error return.
509 bool dir_ask_sysop_to_mount_volume(DCR *dcr)
511 int stat = W_TIMEOUT;
512 DEVICE *dev = dcr->dev;
515 Dmsg0(400, "enter dir_ask_sysop_to_mount_volume\n");
516 if (!dcr->VolumeName[0]) {
517 Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
520 ASSERT(dev->dev_blocked);
522 if (job_canceled(jcr)) {
523 Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
524 jcr->Job, dev->print_name());
533 * If we are not polling, and the wait timeout or the
534 * user explicitly did a mount, send him the message.
537 if (!dev->poll && (stat == W_TIMEOUT || stat == W_MOUNT)) {
538 Jmsg(jcr, M_MOUNT, 0, _("Please mount Volume \"%s\" on Storage Device %s for Job %s\n"),
539 dcr->VolumeName, dev->print_name(), jcr->Job);
540 Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n",
541 dcr->VolumeName, dev->print_name(), jcr->Job);
544 set_jcr_job_status(jcr, JS_WaitMount);
545 dir_send_job_status(jcr);
547 stat = wait_for_sysop(dcr); /* wait on device */
548 Dmsg1(100, "Back from wait_for_sysop stat=%d\n", stat);
550 Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev->print_name());
551 Dmsg1(400, "Blocked=%s\n", dev->print_blocked());
555 if (stat == W_TIMEOUT) {
556 if (!double_dev_wait_time(dev)) {
557 Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
558 dev->print_name(), jcr->Job);
559 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
560 Dmsg1(400, "Gave up waiting on device %s\n", dev->print_name());
561 return false; /* exceeded maximum waits */
565 if (stat == W_ERROR) {
567 Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
568 Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
571 Dmsg1(400, "Someone woke me for device %s\n", dev->print_name());
574 set_jcr_job_status(jcr, JS_Running);
575 dir_send_job_status(jcr);
576 Dmsg0(400, "leave dir_ask_sysop_to_mount_volume\n");