From 292ee206d07d1e85429b214dbc758064476e69c7 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 24 Dec 2007 09:53:46 +0000 Subject: [PATCH] kes Fix seg fault Frank Sweetser reports in regression testing on his systems. The problem was that the original author of bsnprintf.c did not take into account the side effects of using ++x in the argument to a #define. kes Make SD protocol backward compatible with version 2.2.x. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6126 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/patches/2.2.7-reserve.patch | 1467 ++++++++++++++++++++++++++++ bacula/src/dird/ua_restore.c | 6 +- bacula/src/lib/bsnprintf.c | 62 +- bacula/src/lib/message.h | 2 +- bacula/src/stored/acquire.c | 4 +- bacula/src/stored/job.c | 23 +- bacula/technotes-2.3 | 6 + 7 files changed, 1536 insertions(+), 34 deletions(-) create mode 100644 bacula/patches/2.2.7-reserve.patch diff --git a/bacula/patches/2.2.7-reserve.patch b/bacula/patches/2.2.7-reserve.patch new file mode 100644 index 0000000000..42daad1280 --- /dev/null +++ b/bacula/patches/2.2.7-reserve.patch @@ -0,0 +1,1467 @@ + + This patch has a number of cleanups and improvements to the SD + reservations system. It should fix a number of problems with + dual drive autochangers as well ensure that volume use durations + and max volume jobs are better respected. + + Apply it to version 2.2.7 (possibly some earlier versions) with: + + cd + patch -p1 <2.2.7-reserve.patch + ./configure + make + ... + make install + + +diff -ur k1/src/lib/message.c k3/src/lib/message.c +--- k1/src/lib/message.c 2007-10-19 13:47:58.000000000 +0200 ++++ k3/src/lib/message.c 2007-12-22 19:13:00.000000000 +0100 +@@ -54,6 +54,7 @@ + int verbose = 0; /* increase User messages */ + /* Keep debug level set to zero by default */ + int debug_level = 0; /* debug level */ ++bool dbg_timestamp = false; /* print timestamp in debug output */ + time_t daemon_start_time = 0; /* Daemon start time */ + const char *version = VERSION " (" BDATE ")"; + char my_name[30]; /* daemon name is stored here */ +diff -ur k1/src/lib/message.h k3/src/lib/message.h +--- k1/src/lib/message.h 2007-10-03 13:36:47.000000000 +0200 ++++ k3/src/lib/message.h 2007-12-22 19:13:06.000000000 +0100 +@@ -154,6 +154,7 @@ + extern DLL_IMP_EXP sql_escape p_sql_escape; + + extern DLL_IMP_EXP int debug_level; ++extern DLL_IMP_EXP bool dbg_timestamp; /* print timestamp in debug output */ + extern DLL_IMP_EXP int verbose; + extern DLL_IMP_EXP char my_name[]; + extern DLL_IMP_EXP const char * working_directory; +diff -ur k1/src/stored/acquire.c k3/src/stored/acquire.c +--- k1/src/stored/acquire.c 2007-09-14 11:49:06.000000000 +0200 ++++ k3/src/stored/acquire.c 2007-12-22 19:12:23.000000000 +0100 +@@ -30,7 +30,7 @@ + * + * Kern Sibbald, August MMII + * +- * Version $Id: acquire.c 5552 2007-09-14 09:49:06Z kerns $ ++ * Version $Id: acquire.c 6081 2007-12-21 14:11:40Z kerns $ + */ + + #include "bacula.h" /* pull in global headers */ +@@ -38,6 +38,7 @@ + + /* Forward referenced functions */ + static void attach_dcr_to_dev(DCR *dcr); ++static bool is_suitable_volume_mounted(DCR *dcr); + + + /********************************************************************* +@@ -316,9 +317,9 @@ + */ + DCR *acquire_device_for_append(DCR *dcr) + { +- bool release = false; +- bool recycle = false; + bool do_mount = false; ++ bool release = false; ++ bool have_vol; + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; + +@@ -337,6 +338,11 @@ + goto get_out; + } + ++ /* ++ * have_vol defines whether or not mount_next_write_volume should ++ * ask the Director again about what Volume to use. ++ */ ++ have_vol = is_suitable_volume_mounted(dcr); + if (dev->can_append()) { + Dmsg0(190, "device already in append.\n"); + /* +@@ -351,25 +357,11 @@ + * dcr->VolumeName is what we pass into the routines, or + * get back from the subroutines. + */ +- bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName)); +- if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) && ++ if (!have_vol && + !(dir_find_next_appendable_volume(dcr) && + strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */ +- Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName, +- dcr->VolumeName); +- /* Release volume reserved by dir_find_next_appendable_volume() */ +- if (dcr->VolumeName[0]) { +- volume_unused(dcr); +- } +- if (dev->num_writers != 0) { +- Jmsg3(jcr, M_FATAL, 0, _("Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), +- dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName); +- Dmsg3(200, "Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n", +- dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName); +- goto get_out; +- } + /* Wrong tape mounted, release it, then fall through to get correct one */ +- Dmsg0(190, "Wrong tape mounted, release and try mount.\n"); ++ Dmsg0(50, "Wrong tape mounted, release and try mount.\n"); + release = true; + do_mount = true; + } else { +@@ -378,14 +370,17 @@ + * we do not need to do mount_next_write_volume(), unless + * we need to recycle the tape. + */ +- recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0; +- Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle); +- if (recycle && dev->num_writers != 0) { ++ do_mount = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0; ++ Dmsg2(190, "jid=%u Correct tape mounted. recycle=%d\n", ++ (uint32_t)jcr->JobId, do_mount); ++#ifdef xxx ++ if (do_mount && dev->num_writers != 0) { + Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\"" + " on device %s because it is in use by another job.\n"), + dev->VolHdr.VolumeName, dev->print_name()); + goto get_out; + } ++#endif + if (dev->num_writers == 0) { + memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); + } +@@ -415,21 +410,23 @@ + } + } else { + /* Not already in append mode, so mount the device */ +- Dmsg0(190, "Not in append mode, try mount.\n"); ++ Dmsg2(190, "jid=%u Not in append mode, try mount have_vol=%d\n", ++ (uint32_t)jcr->JobId, have_vol); ++ + ASSERT(dev->num_writers == 0); + do_mount = true; + } + +- if (do_mount || recycle) { +- Dmsg0(190, "Do mount_next_write_vol\n"); +- bool mounted = mount_next_write_volume(dcr, release); ++ if (do_mount || !have_vol) { ++ Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId); ++ bool mounted = mount_next_write_volume(dcr, have_vol, release); + if (!mounted) { + if (!job_canceled(jcr)) { + /* Reduce "noise" -- don't print if job canceled */ + Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"), + dev->print_name()); +- Dmsg1(200, "Could not ready device %s for append.\n", +- dev->print_name()); ++ Dmsg2(200, "jid=%u Could not ready device %s for append.\n", ++ (uint32_t)jcr->JobId, dev->print_name()); + } + goto get_out; + } +@@ -441,11 +438,12 @@ + jcr->NumWriteVolumes = 1; + } + dev->VolCatInfo.VolCatJobs++; /* increment number of jobs on vol */ +- dir_update_volume_info(dcr, false); /* send Volume info to Director */ ++ dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ + dev->dlock(); + if (dcr->reserved_device) { + dev->reserved_device--; +- Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); ++ Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, ++ dev->reserved_device, dev->print_name()); + dcr->reserved_device = false; + } + dev->dunblock(DEV_LOCKED); +@@ -458,7 +456,8 @@ + dev->dlock(); + if (dcr->reserved_device) { + dev->reserved_device--; +- Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); ++ Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, ++ dev->reserved_device, dev->print_name()); + dcr->reserved_device = false; + } + dev->dunblock(DEV_LOCKED); +@@ -466,6 +465,18 @@ + } + + ++static bool is_suitable_volume_mounted(DCR *dcr) ++{ ++ DEVICE *dev = dcr->dev; ++ ++ /* Volume mounted? */ ++ if (dev->VolHdr.VolumeName[0] == 0) { ++ return false; /* no */ ++ } ++ bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName)); ++ return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE); ++} ++ + /* + * This job is done, so release the device. From a Unix standpoint, + * the device remains open. +@@ -496,7 +507,7 @@ + if (dev->can_read()) { + dev->clear_read(); /* clear read bit */ + Dmsg0(100, "dir_update_vol_info. Release0\n"); +- dir_update_volume_info(dcr, false); /* send Volume info to Director */ ++ dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ + + } else if (dev->num_writers > 0) { + /* +@@ -522,7 +533,7 @@ + dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */ + /* Note! do volume update before close, which zaps VolCatInfo */ + Dmsg0(100, "dir_update_vol_info. Release0\n"); +- dir_update_volume_info(dcr, false); /* send Volume info to Director */ ++ dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ + } + } + +@@ -621,7 +632,12 @@ + if (dcr->attached_to_dev) { + detach_dcr_from_dev(dcr); + } +- dcr->max_job_spool_size = dev->device->max_job_spool_size; ++ /* Use job spoolsize prior to device spoolsize */ ++ if (jcr->spool_size) { ++ dcr->max_job_spool_size = jcr->spool_size; ++ } else { ++ dcr->max_job_spool_size = dev->device->max_job_spool_size; ++ } + dcr->device = dev->device; + dcr->dev = dev; + attach_dcr_to_dev(dcr); +diff -ur k1/src/stored/askdir.c k3/src/stored/askdir.c +--- k1/src/stored/askdir.c 2007-09-09 12:03:23.000000000 +0200 ++++ k3/src/stored/askdir.c 2007-12-22 19:11:50.000000000 +0100 +@@ -31,7 +31,7 @@ + * + * Kern Sibbald, December 2000 + * +- * Version $Id: askdir.c 5503 2007-09-09 10:03:23Z kerns $ ++ * Version $Id: askdir.c 5852 2007-11-04 19:57:42Z kerns $ + */ + + #include "bacula.h" /* pull in global headers */ +@@ -42,7 +42,7 @@ + static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n"; + static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s" + " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u" +- " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s" ++ " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s" + " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s" + " VolFirstWritten=%s VolParts=%u\n"; + static char Create_job_media[] = "CatReq Job=%s CreateJobMedia" +@@ -98,7 +98,7 @@ + } else { + pm_strcpy(ChangerName, "*"); + } +- ok =bnet_fsend(dir, Device_update, ++ ok = dir->fsend(Device_update, + jcr->Job, + dev_name.c_str(), + dev->can_append()!=0, +@@ -125,7 +125,7 @@ + pm_strcpy(MediaType, device->media_type); + bash_spaces(MediaType); + /* This is mostly to indicate that we are here */ +- ok = bnet_fsend(dir, Device_update, ++ ok = dir->fsend(Device_update, + jcr->Job, + dev_name.c_str(), /* Changer name */ + 0, 0, 0, /* append, read, num_writers */ +@@ -148,7 +148,7 @@ + */ + bool dir_send_job_status(JCR *jcr) + { +- return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus); ++ return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus); + } + + /* +@@ -179,7 +179,7 @@ + return false; + } + memset(&vol, 0, sizeof(vol)); +- Dmsg1(100, "msg); ++ Dmsg1(100, "msg); + n = sscanf(dir->msg, OK_media, vol.VolCatName, + &vol.VolCatJobs, &vol.VolCatFiles, + &vol.VolCatBlocks, &vol.VolCatBytes, +@@ -191,7 +191,8 @@ + &vol.EndFile, &vol.EndBlock, &vol.VolCatParts, + &vol.LabelType, &vol.VolMediaId); + if (n != 22) { +- Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg); ++ Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", ++ n, dir->msglen, dir->msg); + Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg); + return false; + } +@@ -226,7 +227,7 @@ + bash_spaces(dcr->VolCatInfo.VolCatName); + dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName, + writing==GET_VOL_INFO_FOR_WRITE?1:0); +- Dmsg1(100, ">dird: %s\n", dir->msg); ++ Dmsg1(100, ">dird %s", dir->msg); + unbash_spaces(dcr->VolCatInfo.VolCatName); + bool ok = do_get_volume_info(dcr); + V(vol_info_mutex); +@@ -253,7 +254,9 @@ + BSOCK *dir = jcr->dir_bsock; + bool found = false; + +- Dmsg0(200, "dir_find_next_appendable_volume\n"); ++ Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", ++ dcr->reserved_device, dcr->VolumeName); ++ + /* + * Try the twenty oldest or most available volumes. Note, + * the most available could already be mounted on another +@@ -268,7 +271,7 @@ + dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type); + unbash_spaces(dcr->media_type); + unbash_spaces(dcr->pool_name); +- Dmsg1(100, ">dird: %s", dir->msg); ++ Dmsg1(100, ">dird %s", dir->msg); + bool ok = do_get_volume_info(dcr); + if (ok) { + if (!is_volume_in_use(dcr)) { +@@ -311,14 +314,13 @@ + * back to the director. The information comes from the + * dev record. + */ +-bool dir_update_volume_info(DCR *dcr, bool label) ++bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten) + { + JCR *jcr = dcr->jcr; + BSOCK *dir = jcr->dir_bsock; + DEVICE *dev = dcr->dev; +- time_t LastWritten = time(NULL); + VOLUME_CAT_INFO *vol = &dev->VolCatInfo; +- char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50]; ++ char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50]; + int InChanger; + bool ok = false; + POOL_MEM VolumeName; +@@ -341,21 +343,25 @@ + if (label) { + bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus)); + } ++// if (update_LastWritten) { ++ vol->VolLastWritten = time(NULL); ++// } + pm_strcpy(VolumeName, vol->VolCatName); + bash_spaces(VolumeName); + InChanger = vol->InChanger; +- bnet_fsend(dir, Update_media, jcr->Job, ++ dir->fsend(Update_media, jcr->Job, + VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles, + vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1), + vol->VolCatMounts, vol->VolCatErrors, + vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2), +- LastWritten, vol->VolCatStatus, vol->Slot, label, ++ edit_uint64(vol->VolLastWritten, ed6), ++ vol->VolCatStatus, vol->Slot, label, + InChanger, /* bool in structure */ + edit_int64(vol->VolReadTime, ed3), + edit_int64(vol->VolWriteTime, ed4), + edit_uint64(vol->VolFirstWritten, ed5), + vol->VolCatParts); +- Dmsg1(100, ">dird: %s", dir->msg); ++ Dmsg1(100, ">dird %s", dir->msg); + + /* Do not lock device here because it may be locked from label */ + if (!do_get_volume_info(dcr)) { +@@ -364,7 +370,7 @@ + vol->VolCatName, jcr->errmsg); + goto bail_out; + } +- Dmsg1(420, "get_volume_info(): %s", dir->msg); ++ Dmsg1(420, "get_volume_info() %s", dir->msg); + /* Update dev Volume info in case something changed (e.g. expired) */ + dev->VolCatInfo = dcr->VolCatInfo; + ok = true; +@@ -393,20 +399,20 @@ + } + + dcr->WroteVol = false; +- bnet_fsend(dir, Create_job_media, jcr->Job, ++ dir->fsend(Create_job_media, jcr->Job, + dcr->VolFirstIndex, dcr->VolLastIndex, + dcr->StartFile, dcr->EndFile, + dcr->StartBlock, dcr->EndBlock, + dcr->Copy, dcr->Stripe, + edit_uint64(dcr->VolMediaId, ed1)); +- Dmsg1(100, ">dird: %s", dir->msg); ++ Dmsg1(100, ">dird %s", dir->msg); + if (bnet_recv(dir) <= 0) { + Dmsg0(190, "create_jobmedia error bnet_recv\n"); + Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"), +- bnet_strerror(dir)); ++ dir->bstrerror()); + return false; + } +- Dmsg1(100, "msg); ++ Dmsg1(100, "msg); + if (strcmp(dir->msg, OK_create) != 0) { + Dmsg1(130, "Bad response from Dir: %s\n", dir->msg); + Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg); +@@ -429,9 +435,10 @@ + return true; + #endif + +- dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job); +- dir->msg = check_pool_memory_size(dir->msg, dir->msglen + +- sizeof(DEV_RECORD) + rec->data_len); ++ dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) + ++ MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1); ++ dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) + ++ MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job); + ser_begin(dir->msg + dir->msglen, 0); + ser_uint32(rec->VolSessionId); + ser_uint32(rec->VolSessionTime); +@@ -440,8 +447,8 @@ + ser_uint32(rec->data_len); + ser_bytes(rec->data, rec->data_len); + dir->msglen = ser_length(dir->msg); +- Dmsg1(1800, ">dird: %s\n", dir->msg); /* Attributes */ +- return bnet_send(dir); ++ Dmsg1(1800, ">dird %s\n", dir->msg); /* Attributes */ ++ return dir->send(); + } + + +diff -ur k1/src/stored/bcopy.c k3/src/stored/bcopy.c +--- k1/src/stored/bcopy.c 2007-12-03 20:27:38.000000000 +0100 ++++ k3/src/stored/bcopy.c 2007-12-22 19:10:29.000000000 +0100 +@@ -32,7 +32,7 @@ + * Kern E. Sibbald, October 2002 + * + * +- * Version $Id: bcopy.c 6017 2007-12-03 19:27:38Z kerns $ ++ * Version $Id: bcopy.c 6016 2007-12-03 19:27:21Z kerns $ + */ + + #include "bacula.h" +@@ -42,6 +42,7 @@ + int generate_daemon_event(JCR *jcr, const char *event) { return 1; } + + /* Forward referenced functions */ ++static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec); + static bool record_cb(DCR *dcr, DEV_RECORD *rec); + + +@@ -52,10 +53,11 @@ + static JCR *out_jcr; /* output jcr */ + static BSR *bsr = NULL; + static const char *wd = "/tmp"; +-static int list_records = 0; ++static bool list_records = false; + static uint32_t records = 0; + static uint32_t jobs = 0; + static DEV_BLOCK *out_block; ++static SESSION_LABEL sessrec; + + #define CONFIG_FILE "bacula-sd.conf" + char *configfile = NULL; +@@ -73,7 +75,7 @@ + "Usage: bcopy [-d debug_level] \n" + " -b bootstrap specify a bootstrap file\n" + " -c specify configuration file\n" +-" -d set debug level to nn\n" ++" -d set debug level to \n" + " -i specify input Volume names (separated by |)\n" + " -o specify output Volume names (separated by |)\n" + " -p proceed inspite of errors\n" +@@ -113,9 +115,14 @@ + break; + + case 'd': /* debug level */ +- debug_level = atoi(optarg); +- if (debug_level <= 0) +- debug_level = 1; ++ if (*optarg == 't') { ++ dbg_timestamp = true; ++ } else { ++ debug_level = atoi(optarg); ++ if (debug_level <= 0) { ++ debug_level = 1; ++ } ++ } + break; + + case 'i': /* input Volume name */ +@@ -201,6 +208,7 @@ + out_block = out_jcr->dcr->block; + + ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume); ++ + if (ok || out_dev->can_write()) { + if (!write_block_to_device(out_jcr->dcr)) { + Pmsg0(000, _("Write of last block failed.\n")); +@@ -233,6 +241,7 @@ + * + */ + if (rec->FileIndex < 0) { ++ get_session_record(in_dcr->dev, rec, &sessrec); + + if (verbose > 1) { + dump_label_record(in_dcr->dev, rec, 1); +@@ -294,10 +303,46 @@ + return true; + } + ++static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec) ++{ ++ const char *rtype; ++ memset(sessrec, 0, sizeof(sessrec)); ++ switch (rec->FileIndex) { ++ case PRE_LABEL: ++ rtype = _("Fresh Volume Label"); ++ break; ++ case VOL_LABEL: ++ rtype = _("Volume Label"); ++ unser_volume_label(dev, rec); ++ break; ++ case SOS_LABEL: ++ rtype = _("Begin Job Session"); ++ unser_session_label(sessrec, rec); ++ break; ++ case EOS_LABEL: ++ rtype = _("End Job Session"); ++ unser_session_label(sessrec, rec); ++ break; ++ case 0: ++ case EOM_LABEL: ++ rtype = _("End of Medium"); ++ break; ++ default: ++ rtype = _("Unknown"); ++ break; ++ } ++ Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", ++ rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); ++ if (verbose) { ++ Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"), ++ rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); ++ } ++} ++ + + /* Dummies to replace askdir.c */ + bool dir_find_next_appendable_volume(DCR *dcr) { return 1;} +-bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; } ++bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; } + bool dir_create_jobmedia_record(DCR *dcr) { return 1; } + bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } + bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} +diff -ur k1/src/stored/bextract.c k3/src/stored/bextract.c +--- k1/src/stored/bextract.c 2007-10-03 13:36:47.000000000 +0200 ++++ k3/src/stored/bextract.c 2007-12-22 19:10:20.000000000 +0100 +@@ -4,7 +4,7 @@ + * + * Kern E. Sibbald, MM + * +- * Version $Id: bextract.c 5713 2007-10-03 11:36:47Z kerns $ ++ * Version $Id: bextract.c 5852 2007-11-04 19:57:42Z kerns $ + * + */ + /* +@@ -79,7 +79,7 @@ + "Usage: bextract \n" + " -b specify a bootstrap file\n" + " -c specify a configuration file\n" +-" -d set debug level to nn\n" ++" -d set debug level to \n" + " -e exclude list\n" + " -i include list\n" + " -p proceed inspite of I/O errors\n" +@@ -126,9 +126,14 @@ + break; + + case 'd': /* debug level */ +- debug_level = atoi(optarg); +- if (debug_level <= 0) +- debug_level = 1; ++ if (*optarg == 't') { ++ dbg_timestamp = true; ++ } else { ++ debug_level = atoi(optarg); ++ if (debug_level <= 0) { ++ debug_level = 1; ++ } ++ } + break; + + case 'e': /* exclude list */ +@@ -476,7 +481,7 @@ + + /* Dummies to replace askdir.c */ + bool dir_find_next_appendable_volume(DCR *dcr) { return 1;} +-bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; } ++bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; } + bool dir_create_jobmedia_record(DCR *dcr) { return 1; } + bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } + bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} +diff -ur k1/src/stored/block.c k3/src/stored/block.c +--- k1/src/stored/block.c 2007-10-03 13:36:47.000000000 +0200 ++++ k3/src/stored/block.c 2007-12-22 19:12:33.000000000 +0100 +@@ -32,7 +32,7 @@ + * Kern Sibbald, March MMI + * added BB02 format October MMII + * +- * Version $Id: block.c 5713 2007-10-03 11:36:47Z kerns $ ++ * Version $Id: block.c 5852 2007-11-04 19:57:42Z kerns $ + * + */ + +@@ -746,7 +746,7 @@ + dev->VolCatInfo.VolCatParts = dev->num_dvd_parts; + } + +- if (!dir_update_volume_info(dcr, false)) { ++ if (!dir_update_volume_info(dcr, false, true)) { + ok = false; + } + Dmsg1(100, "dir_update_volume_info terminate writing -- %s\n", ok?"OK":"ERROR"); +@@ -798,7 +798,7 @@ + return false; + } + dev->VolCatInfo.VolCatFiles = dev->file; +- if (!dir_update_volume_info(dcr, false)) { ++ if (!dir_update_volume_info(dcr, false, false)) { + Dmsg0(190, "Error from update_vol_info.\n"); + terminate_writing_volume(dcr); + dev->dev_errno = EIO; +@@ -856,7 +856,7 @@ + + dev->VolCatInfo.VolCatParts = dev->num_dvd_parts; + +- if (!dir_update_volume_info(dcr, false)) { ++ if (!dir_update_volume_info(dcr, false, false)) { + Dmsg0(190, "Error from update_vol_info.\n"); + dev->dev_errno = EIO; + return false; +diff -ur k1/src/stored/bls.c k3/src/stored/bls.c +--- k1/src/stored/bls.c 2007-10-03 13:36:47.000000000 +0200 ++++ k3/src/stored/bls.c 2007-12-22 19:10:57.000000000 +0100 +@@ -31,7 +31,7 @@ + * + * Kern Sibbald, MM + * +- * Version $Id: bls.c 5713 2007-10-03 11:36:47Z kerns $ ++ * Version $Id: bls.c 5852 2007-11-04 19:57:42Z kerns $ + */ + + #include "bacula.h" +@@ -79,7 +79,7 @@ + "Usage: bls [options] \n" + " -b specify a bootstrap file\n" + " -c specify a config file\n" +-" -d specify debug level\n" ++" -d set debug level to \n" + " -e exclude list\n" + " -i include list\n" + " -j list jobs\n" +@@ -130,9 +130,14 @@ + break; + + case 'd': /* debug level */ +- debug_level = atoi(optarg); +- if (debug_level <= 0) +- debug_level = 1; ++ if (*optarg == 't') { ++ dbg_timestamp = true; ++ } else { ++ debug_level = atoi(optarg); ++ if (debug_level <= 0) { ++ debug_level = 1; ++ } ++ } + break; + + case 'e': /* exclude list */ +@@ -440,7 +445,7 @@ + + /* Dummies to replace askdir.c */ + bool dir_find_next_appendable_volume(DCR *dcr) { return 1;} +-bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; } ++bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; } + bool dir_create_jobmedia_record(DCR *dcr) { return 1; } + bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } + bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} +diff -ur k1/src/stored/bscan.c k3/src/stored/bscan.c +--- k1/src/stored/bscan.c 2007-10-03 13:36:47.000000000 +0200 ++++ k3/src/stored/bscan.c 2007-12-22 19:11:05.000000000 +0100 +@@ -34,7 +34,7 @@ + * Kern E. Sibbald, December 2001 + * + * +- * Version $Id: bscan.c 5713 2007-10-03 11:36:47Z kerns $ ++ * Version $Id: bscan.c 5852 2007-11-04 19:57:42Z kerns $ + */ + + #include "bacula.h" +@@ -116,7 +116,7 @@ + "Usage: bscan [ options ] \n" + " -b bootstrap specify a bootstrap file\n" + " -c specify configuration file\n" +-" -d set debug level to nn\n" ++" -d set debug level to \n" + " -m update media info in database\n" + " -n specify the database name (default bacula)\n" + " -u specify database user name (default bacula)\n" +@@ -166,9 +166,14 @@ + break; + + case 'd': /* debug level */ +- debug_level = atoi(optarg); +- if (debug_level <= 0) +- debug_level = 1; ++ if (*optarg == 't') { ++ dbg_timestamp = true; ++ } else { ++ debug_level = atoi(optarg); ++ if (debug_level <= 0) { ++ debug_level = 1; ++ } ++ } + break; + + case 'h': +@@ -1271,7 +1276,7 @@ + + /* Dummies to replace askdir.c */ + bool dir_find_next_appendable_volume(DCR *dcr) { return 1;} +-bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; } ++bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; } + bool dir_create_jobmedia_record(DCR *dcr) { return 1; } + bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } + bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} +diff -ur k1/src/stored/btape.c k3/src/stored/btape.c +--- k1/src/stored/btape.c 2007-06-07 16:46:43.000000000 +0200 ++++ k3/src/stored/btape.c 2007-12-22 19:11:14.000000000 +0100 +@@ -37,7 +37,7 @@ + * Note, this program reads stored.conf, and will only + * talk to devices that are configured. + * +- * Version $Id: btape.c 4992 2007-06-07 14:46:43Z kerns $ ++ * Version $Id: btape.c 5852 2007-11-04 19:57:42Z kerns $ + * + */ + +@@ -220,9 +220,13 @@ + break; + + case 'd': /* set debug level */ +- debug_level = atoi(optarg); +- if (debug_level <= 0) { +- debug_level = 1; ++ if (*optarg == 't') { ++ dbg_timestamp = true; ++ } else { ++ debug_level = atoi(optarg); ++ if (debug_level <= 0) { ++ debug_level = 1; ++ } + } + break; + +@@ -2598,7 +2602,7 @@ + "Usage: btape \n" + " -b specify bootstrap file\n" + " -c set configuration file to file\n" +-" -d set debug level to nn\n" ++" -d set debug level to \n" + " -p proceed inspite of I/O errors\n" + " -s turn off signals\n" + " -v be verbose\n" +@@ -2644,7 +2648,7 @@ + bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} + bool dir_send_job_status(JCR *jcr) {return 1;} + +-bool dir_update_volume_info(DCR *dcr, bool relabel) ++bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) + { + return 1; + } +diff -ur k1/src/stored/dev.c k3/src/stored/dev.c +--- k1/src/stored/dev.c 2007-12-02 19:03:17.000000000 +0100 ++++ k3/src/stored/dev.c 2007-12-22 19:11:57.000000000 +0100 +@@ -47,7 +47,7 @@ + * daemon. More complicated coding (double buffering, writer + * thread, ...) is left for a later version. + * +- * Version $Id: dev.c 6011 2007-12-02 18:03:17Z kerns $ ++ * Version $Id: dev.c 5999 2007-11-29 21:36:36Z ricozz $ + */ + + /* +@@ -89,7 +89,7 @@ + /* Forward referenced functions */ + void set_os_device_parameters(DCR *dcr); + static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat); +-static char *mode_to_str(int mode); ++static const char *mode_to_str(int mode); + + /* + * Allocate and initialize the DEVICE structure +@@ -490,7 +490,7 @@ + Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), + be.bstrerror()); + Dmsg1(100, "open failed: %s", errmsg); +- Emsg0(M_FATAL, 0, errmsg); ++ Jmsg1(NULL, M_WARNING, 0, "%s", errmsg); + } else { + dev_errno = 0; + file = 0; +@@ -2468,7 +2468,7 @@ + mt_stat->mt_fileno >= 0; + } + +-static char *modes[] = { ++static const char *modes[] = { + "CREATE_READ_WRITE", + "OPEN_READ_WRITE", + "OPEN_READ_ONLY", +@@ -2476,7 +2476,7 @@ + }; + + +-static char *mode_to_str(int mode) ++static const char *mode_to_str(int mode) + { + static char buf[100]; + if (mode < 1 || mode > 4) { +diff -ur k1/src/stored/dev.h k3/src/stored/dev.h +--- k1/src/stored/dev.h 2007-09-09 12:03:23.000000000 +0200 ++++ k3/src/stored/dev.h 2007-12-22 19:12:14.000000000 +0100 +@@ -31,7 +31,7 @@ + * + * Kern Sibbald, MM + * +- * Version $Id: dev.h 5503 2007-09-09 10:03:23Z kerns $ ++ * Version $Id: dev.h 5852 2007-11-04 19:57:42Z kerns $ + * + */ + +@@ -158,6 +158,7 @@ + btime_t VolWriteTime; /* time spent writing this Volume */ + int64_t VolMediaId; /* MediaId */ + utime_t VolFirstWritten; /* Time of first write */ ++ utime_t VolLastWritten; /* Time of last write */ + bool InChanger; /* Set if vol in current magazine */ + char VolCatStatus[20]; /* Volume status */ + char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ +@@ -473,8 +474,9 @@ + class VOLRES { + public: + dlink link; +- char *vol_name; +- DEVICE *dev; ++ char *vol_name; /* Volume name */ ++ DEVICE *dev; /* Pointer to device to which we are attached */ ++ bool released; /* set when the Volume can be released */ + }; + + +diff -ur k1/src/stored/device.c k3/src/stored/device.c +--- k1/src/stored/device.c 2007-06-29 14:12:26.000000000 +0200 ++++ k3/src/stored/device.c 2007-12-22 19:11:23.000000000 +0100 +@@ -53,7 +53,7 @@ + * + * Kern Sibbald, MM, MMI + * +- * Version $Id: device.c 5114 2007-06-29 12:12:26Z kerns $ ++ * Version $Id: device.c 5852 2007-11-04 19:57:42Z kerns $ + */ + + #include "bacula.h" /* pull in global headers */ +@@ -122,7 +122,8 @@ + edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2), + bstrftime(dt, sizeof(dt), time(NULL))); + +- if (!mount_next_write_volume(dcr, 1)) { ++ /* Called with have_vol=false, release=true */ ++ if (!mount_next_write_volume(dcr, false, true)) { + free_block(label_blk); + dcr->block = block; + dev->dlock(); +@@ -131,7 +132,7 @@ + dev->dlock(); /* lock again */ + + dev->VolCatInfo.VolCatJobs++; /* increment number of jobs on vol */ +- dir_update_volume_info(dcr, false); /* send Volume info to Director */ ++ dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ + + Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"), + dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL))); +diff -ur k1/src/stored/dvd.c k3/src/stored/dvd.c +--- k1/src/stored/dvd.c 2007-06-07 16:46:43.000000000 +0200 ++++ k3/src/stored/dvd.c 2007-12-22 19:26:23.000000000 +0100 +@@ -1,16 +1,7 @@ + /* +- * +- * dvd.c -- Routines specific to DVD devices (and +- * possibly other removable hard media). +- * +- * Nicolas Boichat, MMV +- * +- * Version $Id: dvd.c 4992 2007-06-07 14:46:43Z kerns $ +- */ +-/* + Bacula® - The Network Backup Solution + +- Copyright (C) 2005-2006 Free Software Foundation Europe e.V. ++ Copyright (C) 2005-2007 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. +@@ -34,6 +25,15 @@ + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. + */ ++/* ++ * ++ * dvd.c -- Routines specific to DVD devices (and ++ * possibly other removable hard media). ++ * ++ * Nicolas Boichat, MMV ++ * ++ * Version $Id: dvd.c 5852 2007-11-04 19:57:42Z kerns $ ++ */ + + #include "bacula.h" + #include "stored.h" +@@ -686,7 +686,7 @@ + dcr->VolCatInfo.VolCatBytes = 0; + + /* Update catalog */ +- if (!dir_update_volume_info(dcr, false)) { ++ if (!dir_update_volume_info(dcr, false, true)) { + return false; + } + +diff -ur k1/src/stored/job.c k3/src/stored/job.c +--- k1/src/stored/job.c 2007-09-29 00:01:16.000000000 +0200 ++++ k3/src/stored/job.c 2007-12-22 19:11:41.000000000 +0100 +@@ -30,7 +30,7 @@ + * + * Kern Sibbald, MM + * +- * Version $Id: job.c 5686 2007-09-28 22:01:16Z kerns $ ++ * Version $Id: job.c 5697 2007-09-30 17:40:08Z ricozz $ + * + */ + +@@ -49,9 +49,13 @@ + /* Requests from the Director daemon */ + static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s " + "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s " ++ "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s\n"; ++static char oldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s " ++ "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s " + "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n"; + + ++ + /* Responses sent to Director daemon */ + static char OKjob[] = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n"; + static char BAD_job[] = "3915 Bad Job command. stat=%d CMD: %s\n"; +@@ -73,6 +77,7 @@ + { + int JobId; + char auth_key[100]; ++ char spool_size[30]; + char seed[100]; + BSOCK *dir = jcr->dir_bsock; + POOL_MEM job_name, client_name, job, fileset_name, fileset_md5; +@@ -85,17 +90,26 @@ + * Get JobId and permissions from Director + */ + Dmsg1(100, "msg); ++ bstrncpy(spool_size, "0", sizeof(spool_size)); + stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(), + client_name.c_str(), + &JobType, &level, fileset_name.c_str(), &no_attributes, +- &spool_attributes, fileset_md5.c_str(), &spool_data, ++ &spool_attributes, fileset_md5.c_str(), &spool_data, ++ &write_part_after_job, &PreferMountedVols, spool_size); ++ if (stat != 14) { ++ /* Try old version */ ++ stat = sscanf(dir->msg, oldjobcmd, &JobId, job.c_str(), job_name.c_str(), ++ client_name.c_str(), ++ &JobType, &level, fileset_name.c_str(), &no_attributes, ++ &spool_attributes, fileset_md5.c_str(), &spool_data, + &write_part_after_job, &PreferMountedVols); +- if (stat != 13) { +- pm_strcpy(jcr->errmsg, dir->msg); +- dir->fsend(BAD_job, stat, jcr->errmsg); +- Dmsg1(100, ">dird: %s", dir->msg); +- set_jcr_job_status(jcr, JS_ErrorTerminated); +- return false; ++ if (stat != 13) { ++ pm_strcpy(jcr->errmsg, dir->msg); ++ dir->fsend(BAD_job, stat, jcr->errmsg); ++ Dmsg1(100, ">dird: %s", dir->msg); ++ set_jcr_job_status(jcr, JS_ErrorTerminated); ++ return false; ++ } + } + /* + * Since this job could be rescheduled, we +@@ -125,6 +139,7 @@ + jcr->no_attributes = no_attributes; + jcr->spool_attributes = spool_attributes; + jcr->spool_data = spool_data; ++ jcr->spool_size = str_to_int64(spool_size); + jcr->write_part_after_job = write_part_after_job; + jcr->fileset_md5 = get_pool_memory(PM_NAME); + pm_strcpy(jcr->fileset_md5, fileset_md5); +diff -ur k1/src/stored/label.c k3/src/stored/label.c +--- k1/src/stored/label.c 2007-10-03 13:36:47.000000000 +0200 ++++ k3/src/stored/label.c 2007-12-22 19:10:49.000000000 +0100 +@@ -32,7 +32,7 @@ + * Kern Sibbald, MM + * + * +- * Version $Id: label.c 5713 2007-10-03 11:36:47Z kerns $ ++ * Version $Id: label.c 5852 2007-11-04 19:57:42Z kerns $ + */ + + #include "bacula.h" /* pull in global headers */ +@@ -505,7 +505,7 @@ + } + Dmsg0(150, "dir_update_vol_info. Set Append\n"); + bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus)); +- if (!dir_update_volume_info(dcr, true)) { /* indicate doing relabel */ ++ if (!dir_update_volume_info(dcr, true, true)) { /* indicate doing relabel */ + return false; + } + if (recycle) { +@@ -716,7 +716,7 @@ + } + break; + default: +- Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label); ++ Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label); + break; + } + create_session_label(dcr, rec, label); +diff -ur k1/src/stored/mount.c k3/src/stored/mount.c +--- k1/src/stored/mount.c 2007-09-14 11:49:06.000000000 +0200 ++++ k3/src/stored/mount.c 2007-12-22 19:11:30.000000000 +0100 +@@ -32,7 +32,7 @@ + * + * Kern Sibbald, August MMII + * +- * Version $Id: mount.c 5552 2007-09-14 09:49:06Z kerns $ ++ * Version $Id: mount.c 5852 2007-11-04 19:57:42Z kerns $ + */ + + #include "bacula.h" /* pull in global headers */ +@@ -60,7 +60,7 @@ + * impossible to get the requested Volume. + * + */ +-bool mount_next_write_volume(DCR *dcr, bool release) ++bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release) + { + int retry = 0; + bool ask = false, recycle, autochanger; +@@ -108,12 +108,16 @@ + * in dcr->VolCatInfo + */ + Dmsg0(200, "Before dir_find_next_appendable_volume.\n"); +- while (!dir_find_next_appendable_volume(dcr)) { +- Dmsg0(200, "not dir_find_next\n"); +- if (!dir_ask_sysop_to_create_appendable_volume(dcr)) { +- return false; ++ if (!have_vol) { ++ while (!dir_find_next_appendable_volume(dcr)) { ++ Dmsg0(200, "not dir_find_next\n"); ++ if (!dir_ask_sysop_to_create_appendable_volume(dcr)) { ++ return false; ++ } ++ Dmsg0(200, "Again dir_find_next_append...\n"); + } +- Dmsg0(200, "Again dir_find_next_append...\n"); ++ } else { ++ have_vol = false; /* set false for next pass if any */ + } + if (job_canceled(jcr)) { + return false; +@@ -144,7 +148,7 @@ + * If we autochanged to correct Volume or (we have not just + * released the Volume AND we can automount) we go ahead + * and read the label. If there is no tape in the drive, +- * we will err, recurse and ask the operator the next time. ++ * we will fail, recurse and ask the operator the next time. + */ + if (!release && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) { + Dmsg0(150, "(1)Ask=0\n"); +@@ -432,7 +436,7 @@ + } + dev->VolCatInfo.VolCatMounts++; /* Update mounts */ + Dmsg1(150, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts); +- if (!dir_update_volume_info(dcr, false)) { ++ if (!dir_update_volume_info(dcr, false, false)) { + return false; + } + +@@ -519,7 +523,7 @@ + Dmsg0(150, "dir_update_vol_info. Set Append\n"); + /* Copy Director's info into the device info */ + dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */ +- if (!dir_update_volume_info(dcr, true)) { /* indicate tape labeled */ ++ if (!dir_update_volume_info(dcr, true, true)) { /* indicate tape labeled */ + return try_error; + } + Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"), +@@ -552,7 +556,7 @@ + dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */ + bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus)); + Dmsg0(150, "dir_update_vol_info. Set Error.\n"); +- dir_update_volume_info(dcr, false); ++ dir_update_volume_info(dcr, false, false); + } + + /* +@@ -570,7 +574,7 @@ + dcr->VolCatInfo.InChanger = false; + dev->VolCatInfo.InChanger = false; + Dmsg0(400, "update vol info in mount\n"); +- dir_update_volume_info(dcr, true); /* set new status */ ++ dir_update_volume_info(dcr, true, false); /* set new status */ + } + + /* +@@ -588,6 +592,7 @@ + /* + * First erase all memory of the current volume + */ ++ free_volume(dev); + dev->block_num = dev->file = 0; + dev->EndBlock = dev->EndFile = 0; + memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); +diff -ur k1/src/stored/protos.h k3/src/stored/protos.h +--- k1/src/stored/protos.h 2007-06-28 13:57:03.000000000 +0200 ++++ k3/src/stored/protos.h 2007-12-22 19:12:43.000000000 +0100 +@@ -28,7 +28,7 @@ + /* + * Protypes for stored -- Kern Sibbald MM + * +- * Version $Id: protos.h 5112 2007-06-28 11:57:03Z kerns $ ++ * Version $Id: protos.h 5852 2007-11-04 19:57:42Z kerns $ + */ + + /* From stored.c */ +@@ -49,7 +49,7 @@ + }; + bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw); + bool dir_find_next_appendable_volume(DCR *dcr); +-bool dir_update_volume_info(DCR *dcr, bool label); ++bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten); + bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr); + bool dir_ask_sysop_to_mount_volume(DCR *dcr); + bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec); +@@ -182,7 +182,7 @@ + bool is_this_bsr_done(BSR *bsr, DEV_RECORD *rec); + + /* From mount.c */ +-bool mount_next_write_volume(DCR *dcr, bool release); ++bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release); + bool mount_next_read_volume(DCR *dcr); + void mark_volume_in_error(DCR *dcr); + +diff -ur k1/src/stored/record.c k3/src/stored/record.c +--- k1/src/stored/record.c 2007-06-07 16:46:43.000000000 +0200 ++++ k3/src/stored/record.c 2007-12-22 19:12:06.000000000 +0100 +@@ -1,14 +1,4 @@ + /* +- * +- * record.c -- tape record handling functions +- * +- * Kern Sibbald, April MMI +- * added BB02 format October MMII +- * +- * Version $Id: record.c 4992 2007-06-07 14:46:43Z kerns $ +- * +- */ +-/* + Bacula® - The Network Backup Solution + + Copyright (C) 2001-2006 Free Software Foundation Europe e.V. +@@ -35,6 +25,16 @@ + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. + */ ++/* ++ * ++ * record.c -- tape record handling functions ++ * ++ * Kern Sibbald, April MMI ++ * added BB02 format October MMII ++ * ++ * Version $Id: record.c 6014 2007-12-03 18:14:27Z kerns $ ++ * ++ */ + + + #include "bacula.h" +@@ -254,7 +254,7 @@ + ASSERT(block->buf_len >= block->binbuf); + + Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n" +-"rem=%d remainder=%d\n", ++ "rem=%d remainder=%d\n", + FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, + stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len, + remlen, rec->remainder); +@@ -365,7 +365,7 @@ + if (!sm_check_rtn(__FILE__, __LINE__, False)) { + /* We damaged a buffer */ + Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n" +-"rem=%d remainder=%d\n", ++ "rem=%d remainder=%d\n", + FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, + stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len, + remlen, rec->remainder); +diff -ur k1/src/stored/reserve.c k3/src/stored/reserve.c +--- k1/src/stored/reserve.c 2007-08-04 18:46:32.000000000 +0200 ++++ k3/src/stored/reserve.c 2007-12-22 19:09:56.000000000 +0100 +@@ -212,11 +212,11 @@ + if (dev) { + len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name()); + sendit(msg.c_str(), len, arg); +- len = Mmsg(msg, " Reader=%d writers=%d reserved=%d\n", dev->can_read()?1:0, +- dev->num_writers, dev->reserved_device); ++ len = Mmsg(msg, " Reader=%d writers=%d reserved=%d released=%d\n", ++ dev->can_read()?1:0, dev->num_writers, dev->reserved_device, vol->released); + sendit(msg.c_str(), len, arg); + } else { +- len = Mmsg(msg, "%s no dev\n", vol->vol_name); ++ len = Mmsg(msg, "%s no device. released=%d\n", vol->vol_name, vol->released); + sendit(msg.c_str(), len, arg); + } + } +@@ -292,11 +292,11 @@ + * already exist and are correctly programmed and will need no changes -- use + * counts are always very tricky. + * +- * The old code had a concept of "reserving" a Volume, but it needs to be changed ++ * The old code had a concept of "reserving" a Volume, but was changed + * to reserving and using a drive. A volume is must be attached to (owned by) a + * drive and can move from drive to drive or be unused given certain specific + * conditions of the drive. The key is that the drive must "own" the Volume. +- * The old code has the job (dcr) owning the volume (more or less). The job is ++ * The old code had the job (dcr) owning the volume (more or less). The job was + * to change the insertion and removal of the volumes from the list to be based + * on the drive rather than the job. + * +@@ -329,13 +329,14 @@ + * because it was probably inserted by another job. + */ + if (strcmp(vol->vol_name, VolumeName) == 0) { ++ Dmsg1(dbglvl, "OK, vol=%s on device.\n", VolumeName); + goto get_out; /* Volume already on this device */ + } else { +- Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n", ++ Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n", + (int)dcr->jcr->JobId, vol->vol_name, vol->vol_name); +- debug_list_volumes("reserve_vol free"); + vol_list->remove(vol); + free_vol_item(vol); ++ debug_list_volumes("reserve_vol free"); + } + } + +@@ -378,12 +379,16 @@ + Dmsg4(dbglvl, "jid=%u Volume busy could not swap vol=%s from dev=%s to %s\n", + jid(), VolumeName, vol->dev->print_name(), dev->print_name()); + vol = NULL; /* device busy */ ++ goto get_out; + } + } + } + dev->vol = vol; + + get_out: ++ if (vol) { ++ vol->released = false; ++ } + debug_list_volumes("end new volume"); + unlock_volumes(); + return vol; +@@ -462,6 +467,7 @@ + * explicitly read in this drive. This allows the SD to remember + * where the tapes are or last were. + */ ++ dev->vol->released = true; + if (dev->is_tape() || dev->is_autochanger()) { + return true; + } else { +@@ -837,6 +843,7 @@ + dlist *temp_vol_list, *save_vol_list; + VOLRES *vol = NULL; + lock_volumes(); ++ Dmsg0(dbglvl, "lock volumes\n"); + + /* + * Create a temporary copy of the volume list. We do this, +@@ -1122,6 +1129,26 @@ + */ + if (dcr->volume_in_use && !rctx.PreferMountedVols) { + rctx.PreferMountedVols = true; ++ if (dcr->VolumeName[0]) { ++ volume_unused(dcr); ++ } ++ goto bail_out; ++ } ++ /* ++ * Note. Under some circumstances, the Director can hand us ++ * a Volume name that is no the same as the one on the current ++ * drive, and in that case, the call above to find the next ++ * volume will fail because in attempting to reserve the Volume ++ * the code will realize that we already have a tape mounted, ++ * and it will fail. This *should* only happen if there are ++ * writers, thus the following test. In that case, we simply ++ * bail out, and continue waiting, rather than plunging on ++ * and hoping that the operator can resolve the problem. ++ */ ++ if (dcr->dev->num_writers != 0) { ++ if (dcr->VolumeName[0]) { ++ volume_unused(dcr); ++ } + goto bail_out; + } + } +@@ -1270,6 +1297,51 @@ + return ok; + } + ++static int is_pool_ok(DCR *dcr) ++{ ++ DEVICE *dev = dcr->dev; ++ JCR *jcr = dcr->jcr; ++ ++ /* Now check if we want the same Pool and pool type */ ++ if (strcmp(dev->pool_name, dcr->pool_name) == 0 && ++ strcmp(dev->pool_type, dcr->pool_type) == 0) { ++ /* OK, compatible device */ ++ Dmsg1(dbglvl, "OK dev: %s num_writers=0, reserved, pool matches\n", dev->print_name()); ++ return 1; ++ } else { ++ /* Drive Pool not suitable for us */ ++ Mmsg(jcr->errmsg, _( ++"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), ++ (uint32_t)jcr->JobId, dcr->pool_name, dev->pool_name, ++ dev->reserved_device, dev->print_name()); ++ queue_reserve_message(jcr); ++ Dmsg2(dbglvl, "failed: busy num_writers=0, reserved, pool=%s wanted=%s\n", ++ dev->pool_name, dcr->pool_name); ++ } ++ return 0; ++} ++ ++static bool is_max_jobs_ok(DCR *dcr) ++{ ++ DEVICE *dev = dcr->dev; ++ JCR *jcr = dcr->jcr; ++ ++ Dmsg4(dbglvl, "MaxJobs=%d Jobs=%d reserves=%d Vol=%s\n", ++ dcr->VolCatInfo.VolCatMaxJobs, ++ dcr->VolCatInfo.VolCatJobs, dev->reserved_device, ++ dcr->VolumeName); ++ if (dcr->VolCatInfo.VolCatMaxJobs > 0 && dcr->VolCatInfo.VolCatMaxJobs <= ++ (dcr->VolCatInfo.VolCatJobs + dev->reserved_device)) { ++ /* Max Job Vols depassed or already reserved */ ++ Mmsg(jcr->errmsg, _("3610 JobId=%u Volume max jobs exceeded on drive %s.\n"), ++ (uint32_t)jcr->JobId, dev->print_name()); ++ queue_reserve_message(jcr); ++ Dmsg1(dbglvl, "reserve dev failed: %s", jcr->errmsg); ++ return false; /* wait */ ++ } ++ return true; ++} ++ + /* + * Returns: 1 if drive can be reserved + * 0 if we should wait +@@ -1285,6 +1357,11 @@ + rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device, + rctx.autochanger_only, rctx.any_drive); + ++ /* Check for max jobs on this Volume */ ++ if (!is_max_jobs_ok(dcr)) { ++ return 0; ++ } ++ + /* setting any_drive overrides PreferMountedVols flag */ + if (!rctx.any_drive) { + /* +@@ -1374,32 +1451,10 @@ + if (dev->num_writers == 0) { + /* Now check if there are any reservations on the drive */ + if (dev->reserved_device) { +- /* Now check if we want the same Pool and pool type */ +- if (strcmp(dev->pool_name, dcr->pool_name) == 0 && +- strcmp(dev->pool_type, dcr->pool_type) == 0) { +- /* OK, compatible device */ +- Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, reserved, pool matches\n", +- jcr->JobId, dev->print_name()); +- return 1; +- } else { +- /* Drive Pool not suitable for us */ +- Mmsg(jcr->errmsg, _( +-"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), +- jcr->JobId, dcr->pool_name, dev->pool_name, +- dev->reserved_device, dev->print_name()); +- queue_reserve_message(jcr); +- Dmsg3(dbglvl, "jid=%u failed: busy num_writers=0, reserved, pool=%s wanted=%s\n", +- (int)jcr->JobId, dev->pool_name, dcr->pool_name); +- return 0; /* wait */ +- } ++ return is_pool_ok(dcr); + } else if (dev->can_append()) { +- /* Device in append mode, check if changing pool */ +- if (strcmp(dev->pool_name, dcr->pool_name) == 0 && +- strcmp(dev->pool_type, dcr->pool_type) == 0) { +- Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, can_append, pool matches.\n", +- jcr->JobId, dev->print_name()); +- /* OK, compatible device */ +- return 1; ++ if (is_pool_ok(dcr)) { ++ return 1; + } else { + /* Changing pool, unload old tape if any in drive */ + Dmsg1(dbglvl, "jid=%u OK dev: num_writers=0, not reserved, pool change, unload changer\n", +@@ -1419,22 +1474,7 @@ + * available if pool is the same). + */ + if (dev->can_append() || dev->num_writers > 0) { +- /* Yes, now check if we want the same Pool and pool type */ +- if (strcmp(dev->pool_name, dcr->pool_name) == 0 && +- strcmp(dev->pool_type, dcr->pool_type) == 0) { +- Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers>=0, can_append, pool matches.\n", +- jcr->JobId, dev->print_name()); +- /* OK, compatible device */ +- return 1; +- } else { +- /* Drive Pool not suitable for us */ +- Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"), +- jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name()); +- queue_reserve_message(jcr); +- Dmsg3(dbglvl, "jid=%u failed: busy num_writers>0, can_append, pool=%s wanted=%s\n", +- (int)jcr->JobId, dev->pool_name, dcr->pool_name); +- return 0; /* wait */ +- } ++ return is_pool_ok(dcr); + } else { + Pmsg1(000, _("Logic error!!!! JobId=%u Should not get here.\n"), (int)jcr->JobId); + Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"), diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 9b0dc9090d..06287fcd2e 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -233,7 +233,7 @@ int restore_cmd(UAContext *ua, const char *cmd) escaped_where_name = escape_filename(rx.RegexWhere); Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" - " bootstrap=\"%s\" regexwhere=\"%s\" files=%d catalog=\"%s\"", + " bootstrap=\"%s\" regexwhere=\"%s\" files=%u catalog=\"%s\"", job->name(), rx.ClientName, rx.RestoreClientName, rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, @@ -244,7 +244,7 @@ int restore_cmd(UAContext *ua, const char *cmd) escaped_where_name = escape_filename(rx.where); Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" - " bootstrap=\"%s\" where=\"%s\" files=%d catalog=\"%s\"", + " bootstrap=\"%s\" where=\"%s\" files=%u catalog=\"%s\"", job->name(), rx.ClientName, rx.RestoreClientName, rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, @@ -254,7 +254,7 @@ int restore_cmd(UAContext *ua, const char *cmd) } else { Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" - " bootstrap=\"%s\" files=%d catalog=\"%s\"", + " bootstrap=\"%s\" files=%u catalog=\"%s\"", job->name(), rx.ClientName, rx.RestoreClientName, rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, diff --git a/bacula/src/lib/bsnprintf.c b/bacula/src/lib/bsnprintf.c index 920fdb1b24..4800c3e60a 100644 --- a/bacula/src/lib/bsnprintf.c +++ b/bacula/src/lib/bsnprintf.c @@ -77,8 +77,14 @@ static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen, #define fmtfp(b, c, m, f, min, max, fl) currlen #endif -#define outch(c) {int len=currlen; if (currlen++ < maxlen) { buffer[len] = (c);}} - +/* + * NOTE!!!! do not use this #define with a construct such + * as outch(--place);. It just will NOT work, because the + * decrement of place is done ONLY if there is room in the + * output buffer. + */ +#define outch(c) {int len=currlen; if (currlen < maxlen) \ + { buffer[len] = (c); currlen++; }} /* format read states */ #define DP_S_DEFAULT 0 @@ -102,7 +108,7 @@ static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen, /* Conversion Flags */ #define DP_C_INT16 1 -#define DP_C_INT32 2 +#define DP_C_INT32 2 #define DP_C_LDOUBLE 3 #define DP_C_INT64 4 @@ -152,9 +158,9 @@ int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args) *buffer = 0; while (state != DP_S_DONE) { - if ((ch == '\0') || (currlen >= maxlen)) + if ((ch == '\0') || (currlen >= maxlen)) { state = DP_S_DONE; - + } switch (state) { case DP_S_DEFAULT: if (ch == '%') { @@ -320,7 +326,8 @@ int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args) currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags); break; case 'c': - outch(va_arg(args, int)); + ch = va_arg(args, int); + outch(ch); break; case 's': strvalue = va_arg(args, char *); @@ -400,6 +407,7 @@ static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen, { int padlen, strln; /* amount to pad */ int cnt = 0; + char ch; if (flags & DP_F_DOT && max < 0) { /* Max not specified */ @@ -427,7 +435,8 @@ static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen, --padlen; } while (*value && (cnt < max)) { - outch(*value++); + ch = *value++; + outch(ch); ++cnt; } while (padlen < 0) { @@ -444,11 +453,12 @@ static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen, { int signvalue = 0; uint64_t uvalue; - char convert[20]; + char convert[25]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ int caps = 0; + const char *cvt_string; if (max < 0) { max = 0; @@ -471,12 +481,12 @@ static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen, caps = 1; /* Should characters be upper case? */ } + cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef"; do { - convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") - [uvalue % (unsigned)base]; + convert[place++] = cvt_string[uvalue % (unsigned)base]; uvalue = (uvalue / (unsigned)base); - } while (uvalue && (place < 20)); - if (place == 20) { + } while (uvalue && (place < (int)sizeof(convert))); + if (place == (int)sizeof(convert)) { place--; } convert[place] = 0; @@ -518,9 +528,10 @@ static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen, } } - /* Digits */ + /* Output digits backward giving correct order */ while (place > 0) { - outch(convert[--place]); + place--; + outch(convert[place]); } /* Left Justified spaces */ @@ -573,8 +584,8 @@ static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen, int signvalue = 0; LDOUBLE ufvalue; #ifndef HAVE_FCVT - char iconvert[20]; - char fconvert[20]; + char iconvert[25]; + char fconvert[25]; #else char iconvert[311]; char fconvert[311]; @@ -643,9 +654,10 @@ static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen, iconvert[iplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10]; intpart = (intpart / 10); - } while (intpart && (iplace < 20)); - if (iplace == 20) + } while (intpart && (iplace < (int)sizeof(iplace))); + if (iplace == (int)sizeof(iplace)) { iplace--; + } iconvert[iplace] = 0; /* Convert fractional part */ @@ -653,13 +665,15 @@ static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen, fconvert[fplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10]; fracpart = (fracpart / 10); - } while (fracpart && (fplace < 20)); - if (fplace == 20) + } while (fracpart && (fplace < (int)sizeof(fplace))); + if (fplace == (int)sizeof(fplace)) { fplace--; + } fconvert[fplace] = 0; #else /* use fcvt() */ - if (max > 310) + if (max > 310) { max = 310; + } # ifdef HAVE_FCVTL result = fcvtl(ufvalue, max, &dec_pt, &sig); # else @@ -748,7 +762,8 @@ static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen, } while (iplace > 0) { - outch(iconvert[--iplace]); + iplace--; + outch(iconvert[iplace]); } @@ -763,7 +778,8 @@ static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen, if (max > 0) { outch('.'); while (fplace > 0) { - outch(fconvert[--fplace]); + fplace--; + outch(fconvert[fplace]); } } diff --git a/bacula/src/lib/message.h b/bacula/src/lib/message.h index 4c00f229b9..6d6ff1a833 100644 --- a/bacula/src/lib/message.h +++ b/bacula/src/lib/message.h @@ -154,7 +154,7 @@ extern DLL_IMP_EXP sql_query p_sql_query; extern DLL_IMP_EXP sql_escape p_sql_escape; extern DLL_IMP_EXP int debug_level; -extern DLL_IMP_EXP bool dbg_timestamp; /* print timestamp in debug output */ +extern DLL_IMP_EXP bool dbg_timestamp; /* print timestamp in debug output */ extern DLL_IMP_EXP int verbose; extern DLL_IMP_EXP char my_name[]; extern DLL_IMP_EXP const char * working_directory; diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index c8cb5571f8..6320e12d15 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -339,8 +339,8 @@ DCR *acquire_device_for_append(DCR *dcr) } /* - * find defines whether or not mount_next_write_volume should - * as the Director again about what Volume to use. + * have_vol defines whether or not mount_next_write_volume should + * ask the Director again about what Volume to use. */ have_vol = is_suitable_volume_mounted(dcr); if (dev->can_append()) { diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index ffd666225e..1490fcb011 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -50,6 +50,10 @@ extern bool do_mac(JCR *jcr); static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s " "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s " "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s\n"; +static char oldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s " + "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s " + "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n"; + /* Responses sent to Director daemon */ @@ -86,17 +90,26 @@ bool job_cmd(JCR *jcr) * Get JobId and permissions from Director */ Dmsg1(100, "msg); + bstrncpy(spool_size, "0", sizeof(spool_size)); stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(), client_name.c_str(), &JobType, &level, fileset_name.c_str(), &no_attributes, &spool_attributes, fileset_md5.c_str(), &spool_data, &write_part_after_job, &PreferMountedVols, spool_size); if (stat != 14) { - pm_strcpy(jcr->errmsg, dir->msg); - dir->fsend(BAD_job, stat, jcr->errmsg); - Dmsg1(100, ">dird: %s", dir->msg); - set_jcr_job_status(jcr, JS_ErrorTerminated); - return false; + /* Try old version */ + stat = sscanf(dir->msg, oldjobcmd, &JobId, job.c_str(), job_name.c_str(), + client_name.c_str(), + &JobType, &level, fileset_name.c_str(), &no_attributes, + &spool_attributes, fileset_md5.c_str(), &spool_data, + &write_part_after_job, &PreferMountedVols); + if (stat != 13) { + pm_strcpy(jcr->errmsg, dir->msg); + dir->fsend(BAD_job, stat, jcr->errmsg); + Dmsg1(100, ">dird: %s", dir->msg); + set_jcr_job_status(jcr, JS_ErrorTerminated); + return false; + } } /* * Since this job could be rescheduled, we diff --git a/bacula/technotes-2.3 b/bacula/technotes-2.3 index c30258a7cb..fd47158c78 100644 --- a/bacula/technotes-2.3 +++ b/bacula/technotes-2.3 @@ -1,6 +1,12 @@ Technical notes on version 2.3 General: +24Dec07 +kes Fix seg fault Frank Sweetser reports in regression testing + on his systems. The problem was that the original author of + bsnprintf.c did not take into account the side effects of + using ++x in the argument to a #define. +kes Make SD protocol backward compatible with version 2.2.x. 19Dec07 ebl Fixes bug #1015 where bacula failed to restore acl to a socket because Bacula no longer restores sockets. -- 2.39.5