]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/2.2.7-reserve.patch
ebl build is ok
[bacula/bacula] / bacula / patches / 2.2.7-reserve.patch
1
2  This patch has a number of cleanups and improvements to the SD          
3  reservations system. It should fix a number of problems with
4  dual drive autochangers as well ensure that volume use durations
5  and max volume jobs are better respected.
6
7  Apply it to version 2.2.7 (possibly some earlier versions) with:
8
9  cd <bacula-source>
10  patch -p1 <2.2.7-reserve.patch
11  ./configure <your options>
12  make
13  ...
14  make install
15
16
17 diff -ur k1/src/lib/message.c k3/src/lib/message.c
18 --- k1/src/lib/message.c        2007-10-19 13:47:58.000000000 +0200
19 +++ k3/src/lib/message.c        2007-12-22 19:13:00.000000000 +0100
20 @@ -54,6 +54,7 @@
21  int verbose = 0;                      /* increase User messages */
22  /* Keep debug level set to zero by default */
23  int debug_level = 0;                  /* debug level */
24 +bool dbg_timestamp = false;           /* print timestamp in debug output */
25  time_t daemon_start_time = 0;         /* Daemon start time */
26  const char *version = VERSION " (" BDATE ")";
27  char my_name[30];                     /* daemon name is stored here */
28 diff -ur k1/src/lib/message.h k3/src/lib/message.h
29 --- k1/src/lib/message.h        2007-10-03 13:36:47.000000000 +0200
30 +++ k3/src/lib/message.h        2007-12-22 19:13:06.000000000 +0100
31 @@ -154,6 +154,7 @@
32  extern DLL_IMP_EXP sql_escape    p_sql_escape;
33  
34  extern DLL_IMP_EXP int           debug_level;
35 +extern DLL_IMP_EXP bool          dbg_timestamp;            /* print timestamp in debug output */
36  extern DLL_IMP_EXP int           verbose;
37  extern DLL_IMP_EXP char          my_name[];
38  extern DLL_IMP_EXP const char *  working_directory;
39 diff -ur k1/src/stored/acquire.c k3/src/stored/acquire.c
40 --- k1/src/stored/acquire.c     2007-09-14 11:49:06.000000000 +0200
41 +++ k3/src/stored/acquire.c     2007-12-22 19:12:23.000000000 +0100
42 @@ -30,7 +30,7 @@
43   *
44   *   Kern Sibbald, August MMII
45   *
46 - *   Version $Id: acquire.c 5552 2007-09-14 09:49:06Z kerns $
47 + *   Version $Id: acquire.c 6081 2007-12-21 14:11:40Z kerns $
48   */
49  
50  #include "bacula.h"                   /* pull in global headers */
51 @@ -38,6 +38,7 @@
52  
53  /* Forward referenced functions */
54  static void attach_dcr_to_dev(DCR *dcr);
55 +static bool is_suitable_volume_mounted(DCR *dcr);
56  
57  
58  /*********************************************************************
59 @@ -316,9 +317,9 @@
60   */
61  DCR *acquire_device_for_append(DCR *dcr)
62  {
63 -   bool release = false;
64 -   bool recycle = false;
65     bool do_mount = false;
66 +   bool release = false;
67 +   bool have_vol;
68     DEVICE *dev = dcr->dev;
69     JCR *jcr = dcr->jcr;
70  
71 @@ -337,6 +338,11 @@
72        goto get_out;
73     }
74  
75 +   /*
76 +    * have_vol defines whether or not mount_next_write_volume should
77 +    *   ask the Director again about what Volume to use.
78 +    */
79 +   have_vol = is_suitable_volume_mounted(dcr);
80     if (dev->can_append()) {
81        Dmsg0(190, "device already in append.\n");
82        /*
83 @@ -351,25 +357,11 @@
84         *  dcr->VolumeName is what we pass into the routines, or
85         *    get back from the subroutines.
86         */
87 -      bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
88 -      if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
89 +      if (!have_vol &&
90            !(dir_find_next_appendable_volume(dcr) &&
91              strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
92 -         Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
93 -            dcr->VolumeName);
94 -         /* Release volume reserved by dir_find_next_appendable_volume() */
95 -         if (dcr->VolumeName[0]) {
96 -            volume_unused(dcr);
97 -         }
98 -         if (dev->num_writers != 0) {
99 -            Jmsg3(jcr, M_FATAL, 0, _("Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
100 -                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
101 -            Dmsg3(200, "Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n",  
102 -                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
103 -            goto get_out;
104 -         }
105           /* Wrong tape mounted, release it, then fall through to get correct one */
106 -         Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
107 +         Dmsg0(50, "Wrong tape mounted, release and try mount.\n");
108           release = true;
109           do_mount = true;
110        } else {
111 @@ -378,14 +370,17 @@
112            *   we do not need to do mount_next_write_volume(), unless
113            *   we need to recycle the tape.
114            */
115 -          recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
116 -          Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
117 -          if (recycle && dev->num_writers != 0) {
118 +          do_mount = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
119 +          Dmsg2(190, "jid=%u Correct tape mounted. recycle=%d\n", 
120 +                (uint32_t)jcr->JobId, do_mount);
121 +#ifdef xxx
122 +          if (do_mount && dev->num_writers != 0) {
123               Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
124                    " on device %s because it is in use by another job.\n"),
125                    dev->VolHdr.VolumeName, dev->print_name());
126               goto get_out;
127            }
128 +#endif
129            if (dev->num_writers == 0) {
130               memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
131            }
132 @@ -415,21 +410,23 @@
133        }
134     } else {
135        /* Not already in append mode, so mount the device */
136 -      Dmsg0(190, "Not in append mode, try mount.\n");
137 +      Dmsg2(190, "jid=%u Not in append mode, try mount have_vol=%d\n", 
138 +            (uint32_t)jcr->JobId, have_vol);
139 +
140        ASSERT(dev->num_writers == 0);
141        do_mount = true;
142     }
143  
144 -   if (do_mount || recycle) {
145 -      Dmsg0(190, "Do mount_next_write_vol\n");
146 -      bool mounted = mount_next_write_volume(dcr, release);
147 +   if (do_mount || !have_vol) {
148 +      Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
149 +      bool mounted = mount_next_write_volume(dcr, have_vol, release);
150        if (!mounted) {
151           if (!job_canceled(jcr)) {
152              /* Reduce "noise" -- don't print if job canceled */
153              Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
154                 dev->print_name());
155 -            Dmsg1(200, "Could not ready device %s for append.\n", 
156 -               dev->print_name());
157 +            Dmsg2(200, "jid=%u Could not ready device %s for append.\n", 
158 +               (uint32_t)jcr->JobId, dev->print_name());
159           }
160           goto get_out;
161        }
162 @@ -441,11 +438,12 @@
163        jcr->NumWriteVolumes = 1;
164     }
165     dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
166 -   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
167 +   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
168     dev->dlock();
169     if (dcr->reserved_device) {
170        dev->reserved_device--;
171 -      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
172 +      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId,
173 +            dev->reserved_device, dev->print_name());
174        dcr->reserved_device = false;
175     }
176     dev->dunblock(DEV_LOCKED);
177 @@ -458,7 +456,8 @@
178     dev->dlock();
179     if (dcr->reserved_device) {
180        dev->reserved_device--;
181 -      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
182 +      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, 
183 +            dev->reserved_device, dev->print_name());
184        dcr->reserved_device = false;
185     }
186     dev->dunblock(DEV_LOCKED);
187 @@ -466,6 +465,18 @@
188  }
189  
190  
191 +static bool is_suitable_volume_mounted(DCR *dcr)
192 +{
193 +   DEVICE *dev = dcr->dev;
194 +
195 +   /* Volume mounted? */
196 +   if (dev->VolHdr.VolumeName[0] == 0) {
197 +      return false;                      /* no */
198 +   }
199 +   bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
200 +   return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE);
201 +}
202 +
203  /*
204   * This job is done, so release the device. From a Unix standpoint,
205   *  the device remains open.
206 @@ -496,7 +507,7 @@
207     if (dev->can_read()) {
208        dev->clear_read();              /* clear read bit */
209        Dmsg0(100, "dir_update_vol_info. Release0\n");
210 -      dir_update_volume_info(dcr, false); /* send Volume info to Director */
211 +      dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
212  
213     } else if (dev->num_writers > 0) {
214        /* 
215 @@ -522,7 +533,7 @@
216              dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
217              /* Note! do volume update before close, which zaps VolCatInfo */
218              Dmsg0(100, "dir_update_vol_info. Release0\n");
219 -            dir_update_volume_info(dcr, false); /* send Volume info to Director */
220 +            dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
221           }
222        }
223  
224 @@ -621,7 +632,12 @@
225        if (dcr->attached_to_dev) {
226           detach_dcr_from_dev(dcr);
227        }
228 -      dcr->max_job_spool_size = dev->device->max_job_spool_size;
229 +      /* Use job spoolsize prior to device spoolsize */
230 +      if (jcr->spool_size) {
231 +         dcr->max_job_spool_size = jcr->spool_size;
232 +      } else {
233 +         dcr->max_job_spool_size = dev->device->max_job_spool_size;
234 +      }
235        dcr->device = dev->device;
236        dcr->dev = dev;
237        attach_dcr_to_dev(dcr);
238 diff -ur k1/src/stored/askdir.c k3/src/stored/askdir.c
239 --- k1/src/stored/askdir.c      2007-09-09 12:03:23.000000000 +0200
240 +++ k3/src/stored/askdir.c      2007-12-22 19:11:50.000000000 +0100
241 @@ -31,7 +31,7 @@
242   *
243   *   Kern Sibbald, December 2000
244   *
245 - *   Version $Id: askdir.c 5503 2007-09-09 10:03:23Z kerns $
246 + *   Version $Id: askdir.c 5852 2007-11-04 19:57:42Z kerns $
247   */
248  
249  #include "bacula.h"                   /* pull in global headers */
250 @@ -42,7 +42,7 @@
251  static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
252  static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
253     " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
254 -   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
255 +   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
256     " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
257     " VolFirstWritten=%s VolParts=%u\n";
258  static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
259 @@ -98,7 +98,7 @@
260     } else {
261        pm_strcpy(ChangerName, "*");
262     }
263 -   ok =bnet_fsend(dir, Device_update, 
264 +   ok = dir->fsend(Device_update, 
265        jcr->Job,
266        dev_name.c_str(),
267        dev->can_append()!=0,
268 @@ -125,7 +125,7 @@
269     pm_strcpy(MediaType, device->media_type);
270     bash_spaces(MediaType);
271     /* This is mostly to indicate that we are here */
272 -   ok = bnet_fsend(dir, Device_update,
273 +   ok = dir->fsend(Device_update,
274        jcr->Job,
275        dev_name.c_str(),         /* Changer name */
276        0, 0, 0,                  /* append, read, num_writers */
277 @@ -148,7 +148,7 @@
278   */
279  bool dir_send_job_status(JCR *jcr)
280  {
281 -   return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
282 +   return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus);
283  }
284  
285  /*
286 @@ -179,7 +179,7 @@
287         return false;
288      }
289      memset(&vol, 0, sizeof(vol));
290 -    Dmsg1(100, "<dird %s\n", dir->msg);
291 +    Dmsg1(100, "<dird %s", dir->msg);
292      n = sscanf(dir->msg, OK_media, vol.VolCatName,
293                 &vol.VolCatJobs, &vol.VolCatFiles,
294                 &vol.VolCatBlocks, &vol.VolCatBytes,
295 @@ -191,7 +191,8 @@
296                 &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
297                 &vol.LabelType, &vol.VolMediaId);
298      if (n != 22) {
299 -       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg);
300 +       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
301 +             n, dir->msglen, dir->msg);
302         Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
303         return false;
304      }
305 @@ -226,7 +227,7 @@
306      bash_spaces(dcr->VolCatInfo.VolCatName);
307      dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
308         writing==GET_VOL_INFO_FOR_WRITE?1:0);
309 -    Dmsg1(100, ">dird: %s\n", dir->msg);
310 +    Dmsg1(100, ">dird %s", dir->msg);
311      unbash_spaces(dcr->VolCatInfo.VolCatName);
312      bool ok = do_get_volume_info(dcr);
313      V(vol_info_mutex);
314 @@ -253,7 +254,9 @@
315      BSOCK *dir = jcr->dir_bsock;
316      bool found = false;
317  
318 -    Dmsg0(200, "dir_find_next_appendable_volume\n");
319 +    Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
320 +       dcr->reserved_device, dcr->VolumeName);
321 +
322      /*
323       * Try the twenty oldest or most available volumes.  Note,
324       *   the most available could already be mounted on another
325 @@ -268,7 +271,7 @@
326         dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
327         unbash_spaces(dcr->media_type);
328         unbash_spaces(dcr->pool_name);
329 -       Dmsg1(100, ">dird: %s", dir->msg);
330 +       Dmsg1(100, ">dird %s", dir->msg);
331         bool ok = do_get_volume_info(dcr);
332         if (ok) {
333            if (!is_volume_in_use(dcr)) {
334 @@ -311,14 +314,13 @@
335   * back to the director. The information comes from the
336   * dev record.
337   */
338 -bool dir_update_volume_info(DCR *dcr, bool label)
339 +bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
340  {
341     JCR *jcr = dcr->jcr;
342     BSOCK *dir = jcr->dir_bsock;
343     DEVICE *dev = dcr->dev;
344 -   time_t LastWritten = time(NULL);
345     VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
346 -   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
347 +   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
348     int InChanger;
349     bool ok = false;
350     POOL_MEM VolumeName;
351 @@ -341,21 +343,25 @@
352     if (label) {
353        bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
354     }
355 +// if (update_LastWritten) {
356 +      vol->VolLastWritten = time(NULL);
357 +// }
358     pm_strcpy(VolumeName, vol->VolCatName);
359     bash_spaces(VolumeName);
360     InChanger = vol->InChanger;
361 -   bnet_fsend(dir, Update_media, jcr->Job,
362 +   dir->fsend(Update_media, jcr->Job,
363        VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
364        vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
365        vol->VolCatMounts, vol->VolCatErrors,
366        vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
367 -      LastWritten, vol->VolCatStatus, vol->Slot, label,
368 +      edit_uint64(vol->VolLastWritten, ed6), 
369 +      vol->VolCatStatus, vol->Slot, label,
370        InChanger,                      /* bool in structure */
371        edit_int64(vol->VolReadTime, ed3),
372        edit_int64(vol->VolWriteTime, ed4),
373        edit_uint64(vol->VolFirstWritten, ed5),
374        vol->VolCatParts);
375 -    Dmsg1(100, ">dird: %s", dir->msg);
376 +    Dmsg1(100, ">dird %s", dir->msg);
377  
378     /* Do not lock device here because it may be locked from label */
379     if (!do_get_volume_info(dcr)) {
380 @@ -364,7 +370,7 @@
381           vol->VolCatName, jcr->errmsg);
382        goto bail_out;
383     }
384 -   Dmsg1(420, "get_volume_info(): %s", dir->msg);
385 +   Dmsg1(420, "get_volume_info() %s", dir->msg);
386     /* Update dev Volume info in case something changed (e.g. expired) */
387     dev->VolCatInfo = dcr->VolCatInfo;
388     ok = true;
389 @@ -393,20 +399,20 @@
390     }
391  
392     dcr->WroteVol = false;
393 -   bnet_fsend(dir, Create_job_media, jcr->Job,
394 +   dir->fsend(Create_job_media, jcr->Job,
395        dcr->VolFirstIndex, dcr->VolLastIndex,
396        dcr->StartFile, dcr->EndFile,
397        dcr->StartBlock, dcr->EndBlock, 
398        dcr->Copy, dcr->Stripe, 
399        edit_uint64(dcr->VolMediaId, ed1));
400 -    Dmsg1(100, ">dird: %s", dir->msg);
401 +    Dmsg1(100, ">dird %s", dir->msg);
402     if (bnet_recv(dir) <= 0) {
403        Dmsg0(190, "create_jobmedia error bnet_recv\n");
404        Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
405 -           bnet_strerror(dir));
406 +           dir->bstrerror());
407        return false;
408     }
409 -   Dmsg1(100, "<dir: %s", dir->msg);
410 +   Dmsg1(100, "<dird %s", dir->msg);
411     if (strcmp(dir->msg, OK_create) != 0) {
412        Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
413        Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
414 @@ -429,9 +435,10 @@
415     return true;
416  #endif
417  
418 -   dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
419 -   dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
420 -                sizeof(DEV_RECORD) + rec->data_len);
421 +   dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
422 +                MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
423 +   dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
424 +                MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
425     ser_begin(dir->msg + dir->msglen, 0);
426     ser_uint32(rec->VolSessionId);
427     ser_uint32(rec->VolSessionTime);
428 @@ -440,8 +447,8 @@
429     ser_uint32(rec->data_len);
430     ser_bytes(rec->data, rec->data_len);
431     dir->msglen = ser_length(dir->msg);
432 -   Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
433 -   return bnet_send(dir);
434 +   Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
435 +   return dir->send();
436  }
437  
438  
439 diff -ur k1/src/stored/bcopy.c k3/src/stored/bcopy.c
440 --- k1/src/stored/bcopy.c       2007-12-03 20:27:38.000000000 +0100
441 +++ k3/src/stored/bcopy.c       2007-12-22 19:10:29.000000000 +0100
442 @@ -32,7 +32,7 @@
443   *   Kern E. Sibbald, October 2002
444   *
445   *
446 - *   Version $Id: bcopy.c 6017 2007-12-03 19:27:38Z kerns $
447 + *   Version $Id: bcopy.c 6016 2007-12-03 19:27:21Z kerns $
448   */
449  
450  #include "bacula.h"
451 @@ -42,6 +42,7 @@
452  int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
453  
454  /* Forward referenced functions */
455 +static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
456  static bool record_cb(DCR *dcr, DEV_RECORD *rec);
457  
458  
459 @@ -52,10 +53,11 @@
460  static JCR *out_jcr;                   /* output jcr */
461  static BSR *bsr = NULL;
462  static const char *wd = "/tmp";
463 -static int list_records = 0;
464 +static bool list_records = false;
465  static uint32_t records = 0;
466  static uint32_t jobs = 0;
467  static DEV_BLOCK *out_block;
468 +static SESSION_LABEL sessrec;
469  
470  #define CONFIG_FILE "bacula-sd.conf"
471  char *configfile = NULL;
472 @@ -73,7 +75,7 @@
473  "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
474  "       -b bootstrap      specify a bootstrap file\n"
475  "       -c <file>         specify configuration file\n"
476 -"       -d <nn>           set debug level to nn\n"
477 +"       -d <nn>           set debug level to <nn>\n"
478  "       -i                specify input Volume names (separated by |)\n"
479  "       -o                specify output Volume names (separated by |)\n"
480  "       -p                proceed inspite of errors\n"
481 @@ -113,9 +115,14 @@
482           break;
483  
484        case 'd':                    /* debug level */
485 -         debug_level = atoi(optarg);
486 -         if (debug_level <= 0)
487 -            debug_level = 1;
488 +         if (*optarg == 't') {
489 +            dbg_timestamp = true;
490 +         } else {
491 +            debug_level = atoi(optarg);
492 +            if (debug_level <= 0) {
493 +               debug_level = 1;
494 +            }
495 +         }
496           break;
497  
498        case 'i':                    /* input Volume name */
499 @@ -201,6 +208,7 @@
500     out_block = out_jcr->dcr->block;
501  
502     ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
503 +
504     if (ok || out_dev->can_write()) {
505        if (!write_block_to_device(out_jcr->dcr)) {
506           Pmsg0(000, _("Write of last block failed.\n"));
507 @@ -233,6 +241,7 @@
508      *
509      */
510     if (rec->FileIndex < 0) {
511 +      get_session_record(in_dcr->dev, rec, &sessrec);
512  
513        if (verbose > 1) {
514           dump_label_record(in_dcr->dev, rec, 1);
515 @@ -294,10 +303,46 @@
516     return true;
517  }
518  
519 +static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
520 +{
521 +   const char *rtype;
522 +   memset(sessrec, 0, sizeof(sessrec));
523 +   switch (rec->FileIndex) {
524 +   case PRE_LABEL:
525 +      rtype = _("Fresh Volume Label");
526 +      break;
527 +   case VOL_LABEL:
528 +      rtype = _("Volume Label");
529 +      unser_volume_label(dev, rec);
530 +      break;
531 +   case SOS_LABEL:
532 +      rtype = _("Begin Job Session");
533 +      unser_session_label(sessrec, rec);
534 +      break;
535 +   case EOS_LABEL:
536 +      rtype = _("End Job Session");
537 +      unser_session_label(sessrec, rec);
538 +      break;
539 +   case 0:
540 +   case EOM_LABEL:
541 +      rtype = _("End of Medium");
542 +      break;
543 +   default:
544 +      rtype = _("Unknown");
545 +      break;
546 +   }
547 +   Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
548 +         rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
549 +   if (verbose) {
550 +      Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
551 +            rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
552 +   }
553 +}
554 +
555  
556  /* Dummies to replace askdir.c */
557  bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
558 -bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
559 +bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
560  bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
561  bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
562  bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
563 diff -ur k1/src/stored/bextract.c k3/src/stored/bextract.c
564 --- k1/src/stored/bextract.c    2007-10-03 13:36:47.000000000 +0200
565 +++ k3/src/stored/bextract.c    2007-12-22 19:10:20.000000000 +0100
566 @@ -4,7 +4,7 @@
567   *
568   *   Kern E. Sibbald, MM
569   *
570 - *   Version $Id: bextract.c 5713 2007-10-03 11:36:47Z kerns $
571 + *   Version $Id: bextract.c 5852 2007-11-04 19:57:42Z kerns $
572   *
573   */
574  /*
575 @@ -79,7 +79,7 @@
576  "Usage: bextract <options> <bacula-archive-device-name> <directory-to-store-files>\n"
577  "       -b <file>       specify a bootstrap file\n"
578  "       -c <file>       specify a configuration file\n"
579 -"       -d <nn>         set debug level to nn\n"
580 +"       -d <nn>         set debug level to <nn>\n"
581  "       -e <file>       exclude list\n"
582  "       -i <file>       include list\n"
583  "       -p              proceed inspite of I/O errors\n"
584 @@ -126,9 +126,14 @@
585           break;
586  
587        case 'd':                    /* debug level */
588 -         debug_level = atoi(optarg);
589 -         if (debug_level <= 0)
590 -            debug_level = 1;
591 +         if (*optarg == 't') {
592 +            dbg_timestamp = true;
593 +         } else {
594 +            debug_level = atoi(optarg);
595 +            if (debug_level <= 0) {
596 +               debug_level = 1;
597 +            }
598 +         }
599           break;
600  
601        case 'e':                    /* exclude list */
602 @@ -476,7 +481,7 @@
603  
604  /* Dummies to replace askdir.c */
605  bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
606 -bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
607 +bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
608  bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
609  bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
610  bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
611 diff -ur k1/src/stored/block.c k3/src/stored/block.c
612 --- k1/src/stored/block.c       2007-10-03 13:36:47.000000000 +0200
613 +++ k3/src/stored/block.c       2007-12-22 19:12:33.000000000 +0100
614 @@ -32,7 +32,7 @@
615   *              Kern Sibbald, March MMI
616   *                 added BB02 format October MMII
617   *
618 - *   Version $Id: block.c 5713 2007-10-03 11:36:47Z kerns $
619 + *   Version $Id: block.c 5852 2007-11-04 19:57:42Z kerns $
620   *
621   */
622  
623 @@ -746,7 +746,7 @@
624        dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
625     }
626     
627 -   if (!dir_update_volume_info(dcr, false)) {
628 +   if (!dir_update_volume_info(dcr, false, true)) {
629        ok = false;
630     }
631     Dmsg1(100, "dir_update_volume_info terminate writing -- %s\n", ok?"OK":"ERROR");
632 @@ -798,7 +798,7 @@
633        return false;
634     }
635     dev->VolCatInfo.VolCatFiles = dev->file;
636 -   if (!dir_update_volume_info(dcr, false)) {
637 +   if (!dir_update_volume_info(dcr, false, false)) {
638        Dmsg0(190, "Error from update_vol_info.\n");
639        terminate_writing_volume(dcr);
640        dev->dev_errno = EIO;
641 @@ -856,7 +856,7 @@
642        
643        dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
644              
645 -      if (!dir_update_volume_info(dcr, false)) {
646 +      if (!dir_update_volume_info(dcr, false, false)) {
647           Dmsg0(190, "Error from update_vol_info.\n");
648           dev->dev_errno = EIO;
649           return false;
650 diff -ur k1/src/stored/bls.c k3/src/stored/bls.c
651 --- k1/src/stored/bls.c 2007-10-03 13:36:47.000000000 +0200
652 +++ k3/src/stored/bls.c 2007-12-22 19:10:57.000000000 +0100
653 @@ -31,7 +31,7 @@
654   * 
655   *  Kern Sibbald, MM
656   *
657 - *   Version $Id: bls.c 5713 2007-10-03 11:36:47Z kerns $
658 + *   Version $Id: bls.c 5852 2007-11-04 19:57:42Z kerns $
659   */
660  
661  #include "bacula.h"
662 @@ -79,7 +79,7 @@
663  "Usage: bls [options] <device-name>\n"
664  "       -b <file>       specify a bootstrap file\n"
665  "       -c <file>       specify a config file\n"
666 -"       -d <level>      specify debug level\n"
667 +"       -d <nn>         set debug level to <nn>\n"
668  "       -e <file>       exclude list\n"
669  "       -i <file>       include list\n"
670  "       -j              list jobs\n"
671 @@ -130,9 +130,14 @@
672           break;
673  
674        case 'd':                    /* debug level */
675 -         debug_level = atoi(optarg);
676 -         if (debug_level <= 0)
677 -            debug_level = 1;
678 +         if (*optarg == 't') {
679 +            dbg_timestamp = true;
680 +         } else {
681 +            debug_level = atoi(optarg);
682 +            if (debug_level <= 0) {
683 +               debug_level = 1;
684 +            }
685 +         }
686           break;
687  
688        case 'e':                    /* exclude list */
689 @@ -440,7 +445,7 @@
690  
691  /* Dummies to replace askdir.c */
692  bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
693 -bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
694 +bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
695  bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
696  bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
697  bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
698 diff -ur k1/src/stored/bscan.c k3/src/stored/bscan.c
699 --- k1/src/stored/bscan.c       2007-10-03 13:36:47.000000000 +0200
700 +++ k3/src/stored/bscan.c       2007-12-22 19:11:05.000000000 +0100
701 @@ -34,7 +34,7 @@
702   *   Kern E. Sibbald, December 2001
703   *
704   *
705 - *   Version $Id: bscan.c 5713 2007-10-03 11:36:47Z kerns $
706 + *   Version $Id: bscan.c 5852 2007-11-04 19:57:42Z kerns $
707   */
708  
709  #include "bacula.h"
710 @@ -116,7 +116,7 @@
711  "Usage: bscan [ options ] <bacula-archive>\n"
712  "       -b bootstrap      specify a bootstrap file\n"
713  "       -c <file>         specify configuration file\n"
714 -"       -d <nn>           set debug level to nn\n"
715 +"       -d <nn>           set debug level to <nn>\n"
716  "       -m                update media info in database\n"
717  "       -n <name>         specify the database name (default bacula)\n"
718  "       -u <user>         specify database user name (default bacula)\n"
719 @@ -166,9 +166,14 @@
720           break;
721  
722        case 'd':                    /* debug level */
723 -         debug_level = atoi(optarg);
724 -         if (debug_level <= 0)
725 -            debug_level = 1;
726 +         if (*optarg == 't') {
727 +            dbg_timestamp = true;
728 +         } else {
729 +            debug_level = atoi(optarg);
730 +            if (debug_level <= 0) {
731 +               debug_level = 1;
732 +            }
733 +         }
734           break;
735  
736        case 'h':
737 @@ -1271,7 +1276,7 @@
738  
739  /* Dummies to replace askdir.c */
740  bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
741 -bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
742 +bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
743  bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
744  bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
745  bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
746 diff -ur k1/src/stored/btape.c k3/src/stored/btape.c
747 --- k1/src/stored/btape.c       2007-06-07 16:46:43.000000000 +0200
748 +++ k3/src/stored/btape.c       2007-12-22 19:11:14.000000000 +0100
749 @@ -37,7 +37,7 @@
750   *   Note, this program reads stored.conf, and will only
751   *     talk to devices that are configured.
752   *
753 - *   Version $Id: btape.c 4992 2007-06-07 14:46:43Z kerns $
754 + *   Version $Id: btape.c 5852 2007-11-04 19:57:42Z kerns $
755   *
756   */
757  
758 @@ -220,9 +220,13 @@
759           break;
760  
761        case 'd':                    /* set debug level */
762 -         debug_level = atoi(optarg);
763 -         if (debug_level <= 0) {
764 -            debug_level = 1;
765 +         if (*optarg == 't') {
766 +            dbg_timestamp = true;
767 +         } else {
768 +            debug_level = atoi(optarg);
769 +            if (debug_level <= 0) {
770 +               debug_level = 1;
771 +            }
772           }
773           break;
774  
775 @@ -2598,7 +2602,7 @@
776  "Usage: btape <options> <device_name>\n"
777  "       -b <file>   specify bootstrap file\n"
778  "       -c <file>   set configuration file to file\n"
779 -"       -d <nn>     set debug level to nn\n"
780 +"       -d <nn>     set debug level to <nn>\n"
781  "       -p          proceed inspite of I/O errors\n"
782  "       -s          turn off signals\n"
783  "       -v          be verbose\n"
784 @@ -2644,7 +2648,7 @@
785  bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
786  bool    dir_send_job_status(JCR *jcr) {return 1;}
787  
788 -bool dir_update_volume_info(DCR *dcr, bool relabel)
789 +bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten)
790  {
791     return 1;
792  }
793 diff -ur k1/src/stored/dev.c k3/src/stored/dev.c
794 --- k1/src/stored/dev.c 2007-12-02 19:03:17.000000000 +0100
795 +++ k3/src/stored/dev.c 2007-12-22 19:11:57.000000000 +0100
796 @@ -47,7 +47,7 @@
797   *     daemon. More complicated coding (double buffering, writer
798   *     thread, ...) is left for a later version.
799   *
800 - *   Version $Id: dev.c 6011 2007-12-02 18:03:17Z kerns $
801 + *   Version $Id: dev.c 5999 2007-11-29 21:36:36Z ricozz $
802   */
803  
804  /*
805 @@ -89,7 +89,7 @@
806  /* Forward referenced functions */
807  void set_os_device_parameters(DCR *dcr);   
808  static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
809 -static char *mode_to_str(int mode);
810 +static const char *mode_to_str(int mode);
811  
812  /*
813   * Allocate and initialize the DEVICE structure
814 @@ -490,7 +490,7 @@
815        Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), 
816              be.bstrerror());
817        Dmsg1(100, "open failed: %s", errmsg);
818 -      Emsg0(M_FATAL, 0, errmsg);
819 +      Jmsg1(NULL, M_WARNING, 0, "%s", errmsg);
820     } else {
821        dev_errno = 0;
822        file = 0;
823 @@ -2468,7 +2468,7 @@
824            mt_stat->mt_fileno >= 0;
825  }
826  
827 -static char *modes[] = {
828 +static const char *modes[] = {
829     "CREATE_READ_WRITE",
830     "OPEN_READ_WRITE",
831     "OPEN_READ_ONLY",
832 @@ -2476,7 +2476,7 @@
833  };
834  
835  
836 -static char *mode_to_str(int mode)  
837 +static const char *mode_to_str(int mode)  
838  {
839     static char buf[100];
840     if (mode < 1 || mode > 4) {
841 diff -ur k1/src/stored/dev.h k3/src/stored/dev.h
842 --- k1/src/stored/dev.h 2007-09-09 12:03:23.000000000 +0200
843 +++ k3/src/stored/dev.h 2007-12-22 19:12:14.000000000 +0100
844 @@ -31,7 +31,7 @@
845   *
846   * Kern Sibbald, MM
847   *
848 - *   Version $Id: dev.h 5503 2007-09-09 10:03:23Z kerns $
849 + *   Version $Id: dev.h 5852 2007-11-04 19:57:42Z kerns $
850   *
851   */
852  
853 @@ -158,6 +158,7 @@
854     btime_t  VolWriteTime;             /* time spent writing this Volume */
855     int64_t  VolMediaId;               /* MediaId */
856     utime_t  VolFirstWritten;          /* Time of first write */
857 +   utime_t  VolLastWritten;           /* Time of last write */
858     bool     InChanger;                /* Set if vol in current magazine */
859     char VolCatStatus[20];             /* Volume status */
860     char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
861 @@ -473,8 +474,9 @@
862  class VOLRES { 
863  public:
864     dlink link;
865 -   char *vol_name;
866 -   DEVICE *dev;
867 +   char *vol_name;                    /* Volume name */
868 +   DEVICE *dev;                       /* Pointer to device to which we are attached */
869 +   bool released;                     /* set when the Volume can be released */
870  };
871  
872  
873 diff -ur k1/src/stored/device.c k3/src/stored/device.c
874 --- k1/src/stored/device.c      2007-06-29 14:12:26.000000000 +0200
875 +++ k3/src/stored/device.c      2007-12-22 19:11:23.000000000 +0100
876 @@ -53,7 +53,7 @@
877   *
878   *   Kern Sibbald, MM, MMI
879   *
880 - *   Version $Id: device.c 5114 2007-06-29 12:12:26Z kerns $
881 + *   Version $Id: device.c 5852 2007-11-04 19:57:42Z kerns $
882   */
883  
884  #include "bacula.h"                   /* pull in global headers */
885 @@ -122,7 +122,8 @@
886          edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
887          bstrftime(dt, sizeof(dt), time(NULL)));
888  
889 -   if (!mount_next_write_volume(dcr, 1)) {
890 +   /* Called with have_vol=false, release=true */
891 +   if (!mount_next_write_volume(dcr, false, true)) {
892        free_block(label_blk);
893        dcr->block = block;
894        dev->dlock();  
895 @@ -131,7 +132,7 @@
896     dev->dlock();                    /* lock again */
897  
898     dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
899 -   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
900 +   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
901  
902     Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"),
903        dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL)));
904 diff -ur k1/src/stored/dvd.c k3/src/stored/dvd.c
905 --- k1/src/stored/dvd.c 2007-06-07 16:46:43.000000000 +0200
906 +++ k3/src/stored/dvd.c 2007-12-22 19:26:23.000000000 +0100
907 @@ -1,16 +1,7 @@
908  /*
909 - *
910 - *   dvd.c  -- Routines specific to DVD devices (and
911 - *             possibly other removable hard media). 
912 - *
913 - *    Nicolas Boichat, MMV
914 - *
915 - *   Version $Id: dvd.c 4992 2007-06-07 14:46:43Z kerns $
916 - */
917 -/*
918     Bacula® - The Network Backup Solution
919  
920 -   Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
921 +   Copyright (C) 2005-2007 Free Software Foundation Europe e.V.
922  
923     The main author of Bacula is Kern Sibbald, with contributions from
924     many others, a complete list can be found in the file AUTHORS.
925 @@ -34,6 +25,15 @@
926     (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
927     Switzerland, email:ftf@fsfeurope.org.
928  */
929 +/*
930 + *
931 + *   dvd.c  -- Routines specific to DVD devices (and
932 + *             possibly other removable hard media). 
933 + *
934 + *    Nicolas Boichat, MMV
935 + *
936 + *   Version $Id: dvd.c 5852 2007-11-04 19:57:42Z kerns $
937 + */
938  
939  #include "bacula.h"
940  #include "stored.h"
941 @@ -686,7 +686,7 @@
942     dcr->VolCatInfo.VolCatBytes = 0;
943  
944     /* Update catalog */
945 -   if (!dir_update_volume_info(dcr, false)) {
946 +   if (!dir_update_volume_info(dcr, false, true)) {
947        return false;
948     }
949     
950 diff -ur k1/src/stored/job.c k3/src/stored/job.c
951 --- k1/src/stored/job.c 2007-09-29 00:01:16.000000000 +0200
952 +++ k3/src/stored/job.c 2007-12-22 19:11:41.000000000 +0100
953 @@ -30,7 +30,7 @@
954   *
955   *   Kern Sibbald, MM
956   *
957 - *   Version $Id: job.c 5686 2007-09-28 22:01:16Z kerns $
958 + *   Version $Id: job.c 5697 2007-09-30 17:40:08Z ricozz $
959   *
960   */
961  
962 @@ -49,9 +49,13 @@
963  /* Requests from the Director daemon */
964  static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
965        "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
966 +      "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s\n";
967 +static char oldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
968 +      "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
969        "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
970  
971  
972 +
973  /* Responses sent to Director daemon */
974  static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
975  static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
976 @@ -73,6 +77,7 @@
977  {
978     int JobId;
979     char auth_key[100];
980 +   char spool_size[30];
981     char seed[100];
982     BSOCK *dir = jcr->dir_bsock;
983     POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
984 @@ -85,17 +90,26 @@
985      * Get JobId and permissions from Director
986      */
987     Dmsg1(100, "<dird: %s", dir->msg);
988 +   bstrncpy(spool_size, "0", sizeof(spool_size));
989     stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
990                client_name.c_str(),
991                &JobType, &level, fileset_name.c_str(), &no_attributes,
992 -              &spool_attributes, fileset_md5.c_str(), &spool_data, 
993 +              &spool_attributes, fileset_md5.c_str(), &spool_data,
994 +              &write_part_after_job, &PreferMountedVols, spool_size);
995 +   if (stat != 14) {
996 +      /* Try old version */
997 +      stat = sscanf(dir->msg, oldjobcmd, &JobId, job.c_str(), job_name.c_str(),
998 +              client_name.c_str(),
999 +              &JobType, &level, fileset_name.c_str(), &no_attributes,
1000 +              &spool_attributes, fileset_md5.c_str(), &spool_data,
1001                &write_part_after_job, &PreferMountedVols);
1002 -   if (stat != 13) {
1003 -      pm_strcpy(jcr->errmsg, dir->msg);
1004 -      dir->fsend(BAD_job, stat, jcr->errmsg);
1005 -      Dmsg1(100, ">dird: %s", dir->msg);
1006 -      set_jcr_job_status(jcr, JS_ErrorTerminated);
1007 -      return false;
1008 +      if (stat != 13) {
1009 +         pm_strcpy(jcr->errmsg, dir->msg);
1010 +         dir->fsend(BAD_job, stat, jcr->errmsg);
1011 +         Dmsg1(100, ">dird: %s", dir->msg);
1012 +         set_jcr_job_status(jcr, JS_ErrorTerminated);
1013 +         return false;
1014 +      }
1015     }
1016     /*
1017      * Since this job could be rescheduled, we
1018 @@ -125,6 +139,7 @@
1019     jcr->no_attributes = no_attributes;
1020     jcr->spool_attributes = spool_attributes;
1021     jcr->spool_data = spool_data;
1022 +   jcr->spool_size = str_to_int64(spool_size);
1023     jcr->write_part_after_job = write_part_after_job;
1024     jcr->fileset_md5 = get_pool_memory(PM_NAME);
1025     pm_strcpy(jcr->fileset_md5, fileset_md5);
1026 diff -ur k1/src/stored/label.c k3/src/stored/label.c
1027 --- k1/src/stored/label.c       2007-10-03 13:36:47.000000000 +0200
1028 +++ k3/src/stored/label.c       2007-12-22 19:10:49.000000000 +0100
1029 @@ -32,7 +32,7 @@
1030   *   Kern Sibbald, MM
1031   *
1032   *
1033 - *   Version $Id: label.c 5713 2007-10-03 11:36:47Z kerns $
1034 + *   Version $Id: label.c 5852 2007-11-04 19:57:42Z kerns $
1035   */
1036  
1037  #include "bacula.h"                   /* pull in global headers */
1038 @@ -505,7 +505,7 @@
1039     }
1040     Dmsg0(150, "dir_update_vol_info. Set Append\n");
1041     bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
1042 -   if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
1043 +   if (!dir_update_volume_info(dcr, true, true)) {  /* indicate doing relabel */
1044        return false;
1045     }
1046     if (recycle) {
1047 @@ -716,7 +716,7 @@
1048        }
1049        break;
1050     default:
1051 -      Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
1052 +      Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
1053        break;
1054     }
1055     create_session_label(dcr, rec, label);
1056 diff -ur k1/src/stored/mount.c k3/src/stored/mount.c
1057 --- k1/src/stored/mount.c       2007-09-14 11:49:06.000000000 +0200
1058 +++ k3/src/stored/mount.c       2007-12-22 19:11:30.000000000 +0100
1059 @@ -32,7 +32,7 @@
1060   *
1061   *   Kern Sibbald, August MMII
1062   *
1063 - *   Version $Id: mount.c 5552 2007-09-14 09:49:06Z kerns $
1064 + *   Version $Id: mount.c 5852 2007-11-04 19:57:42Z kerns $
1065   */
1066  
1067  #include "bacula.h"                   /* pull in global headers */
1068 @@ -60,7 +60,7 @@
1069   *  impossible to get the requested Volume.
1070   *
1071   */
1072 -bool mount_next_write_volume(DCR *dcr, bool release)
1073 +bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release)
1074  {
1075     int retry = 0;
1076     bool ask = false, recycle, autochanger;
1077 @@ -108,12 +108,16 @@
1078      *    in dcr->VolCatInfo
1079      */
1080     Dmsg0(200, "Before dir_find_next_appendable_volume.\n");
1081 -   while (!dir_find_next_appendable_volume(dcr)) {
1082 -       Dmsg0(200, "not dir_find_next\n");
1083 -       if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
1084 -         return false;
1085 +   if (!have_vol) {
1086 +      while (!dir_find_next_appendable_volume(dcr)) {
1087 +         Dmsg0(200, "not dir_find_next\n");
1088 +         if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
1089 +            return false;
1090 +          }
1091 +          Dmsg0(200, "Again dir_find_next_append...\n");
1092         }
1093 -       Dmsg0(200, "Again dir_find_next_append...\n");
1094 +   } else {
1095 +      have_vol = false;               /* set false for next pass if any */
1096     }
1097     if (job_canceled(jcr)) {
1098        return false;
1099 @@ -144,7 +148,7 @@
1100      * If we autochanged to correct Volume or (we have not just
1101      *   released the Volume AND we can automount) we go ahead
1102      *   and read the label. If there is no tape in the drive,
1103 -    *   we will err, recurse and ask the operator the next time.
1104 +    *   we will fail, recurse and ask the operator the next time.
1105      */
1106     if (!release && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) {
1107        Dmsg0(150, "(1)Ask=0\n");
1108 @@ -432,7 +436,7 @@
1109        }
1110        dev->VolCatInfo.VolCatMounts++;      /* Update mounts */
1111        Dmsg1(150, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts);
1112 -      if (!dir_update_volume_info(dcr, false)) {
1113 +      if (!dir_update_volume_info(dcr, false, false)) {
1114           return false;
1115        }
1116        
1117 @@ -519,7 +523,7 @@
1118        Dmsg0(150, "dir_update_vol_info. Set Append\n");
1119        /* Copy Director's info into the device info */
1120        dev->VolCatInfo = dcr->VolCatInfo;    /* structure assignment */
1121 -      if (!dir_update_volume_info(dcr, true)) {  /* indicate tape labeled */
1122 +      if (!dir_update_volume_info(dcr, true, true)) {  /* indicate tape labeled */
1123           return try_error;
1124        }
1125        Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
1126 @@ -552,7 +556,7 @@
1127     dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
1128     bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
1129     Dmsg0(150, "dir_update_vol_info. Set Error.\n");
1130 -   dir_update_volume_info(dcr, false);
1131 +   dir_update_volume_info(dcr, false, false);
1132  }
1133  
1134  /*
1135 @@ -570,7 +574,7 @@
1136     dcr->VolCatInfo.InChanger = false;
1137     dev->VolCatInfo.InChanger = false;
1138     Dmsg0(400, "update vol info in mount\n");
1139 -   dir_update_volume_info(dcr, true);  /* set new status */
1140 +   dir_update_volume_info(dcr, true, false);  /* set new status */
1141  }
1142  
1143  /*
1144 @@ -588,6 +592,7 @@
1145     /*
1146      * First erase all memory of the current volume
1147      */
1148 +   free_volume(dev);
1149     dev->block_num = dev->file = 0;
1150     dev->EndBlock = dev->EndFile = 0;
1151     memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
1152 diff -ur k1/src/stored/protos.h k3/src/stored/protos.h
1153 --- k1/src/stored/protos.h      2007-06-28 13:57:03.000000000 +0200
1154 +++ k3/src/stored/protos.h      2007-12-22 19:12:43.000000000 +0100
1155 @@ -28,7 +28,7 @@
1156  /*
1157   * Protypes for stored -- Kern Sibbald MM  
1158   *
1159 - *   Version $Id: protos.h 5112 2007-06-28 11:57:03Z kerns $
1160 + *   Version $Id: protos.h 5852 2007-11-04 19:57:42Z kerns $
1161   */
1162  
1163  /* From stored.c */
1164 @@ -49,7 +49,7 @@
1165  };
1166  bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw);
1167  bool    dir_find_next_appendable_volume(DCR *dcr);
1168 -bool    dir_update_volume_info(DCR *dcr, bool label);
1169 +bool    dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten);
1170  bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr);
1171  bool    dir_ask_sysop_to_mount_volume(DCR *dcr);
1172  bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec);
1173 @@ -182,7 +182,7 @@
1174  bool     is_this_bsr_done(BSR *bsr, DEV_RECORD *rec);
1175  
1176  /* From mount.c */
1177 -bool     mount_next_write_volume(DCR *dcr, bool release);
1178 +bool     mount_next_write_volume(DCR *dcr, bool have_vol, bool release);
1179  bool     mount_next_read_volume(DCR *dcr);
1180  void     mark_volume_in_error(DCR *dcr);
1181  
1182 diff -ur k1/src/stored/record.c k3/src/stored/record.c
1183 --- k1/src/stored/record.c      2007-06-07 16:46:43.000000000 +0200
1184 +++ k3/src/stored/record.c      2007-12-22 19:12:06.000000000 +0100
1185 @@ -1,14 +1,4 @@
1186  /*
1187 - *
1188 - *   record.c -- tape record handling functions
1189 - *
1190 - *              Kern Sibbald, April MMI
1191 - *                added BB02 format October MMII
1192 - *
1193 - *   Version $Id: record.c 4992 2007-06-07 14:46:43Z kerns $
1194 - *
1195 - */
1196 -/*
1197     Bacula® - The Network Backup Solution
1198  
1199     Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
1200 @@ -35,6 +25,16 @@
1201     (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
1202     Switzerland, email:ftf@fsfeurope.org.
1203  */
1204 +/*
1205 + *
1206 + *   record.c -- tape record handling functions
1207 + *
1208 + *              Kern Sibbald, April MMI
1209 + *                added BB02 format October MMII
1210 + *
1211 + *   Version $Id: record.c 6014 2007-12-03 18:14:27Z kerns $
1212 + *
1213 + */
1214  
1215  
1216  #include "bacula.h"
1217 @@ -254,7 +254,7 @@
1218     ASSERT(block->buf_len >= block->binbuf);
1219  
1220     Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
1221 -"rem=%d remainder=%d\n",
1222 +      "rem=%d remainder=%d\n",
1223        FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
1224        stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
1225        remlen, rec->remainder);
1226 @@ -365,7 +365,7 @@
1227           if (!sm_check_rtn(__FILE__, __LINE__, False)) {
1228              /* We damaged a buffer */
1229              Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
1230 -"rem=%d remainder=%d\n",
1231 +               "rem=%d remainder=%d\n",
1232                 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
1233                 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
1234                 remlen, rec->remainder);
1235 diff -ur k1/src/stored/reserve.c k3/src/stored/reserve.c
1236 --- k1/src/stored/reserve.c     2007-08-04 18:46:32.000000000 +0200
1237 +++ k3/src/stored/reserve.c     2007-12-22 19:09:56.000000000 +0100
1238 @@ -212,11 +212,11 @@
1239        if (dev) {
1240           len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
1241           sendit(msg.c_str(), len, arg);
1242 -         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d\n", dev->can_read()?1:0,
1243 -            dev->num_writers, dev->reserved_device);
1244 +         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d released=%d\n", 
1245 +            dev->can_read()?1:0, dev->num_writers, dev->reserved_device, vol->released);
1246           sendit(msg.c_str(), len, arg);
1247        } else {
1248 -         len = Mmsg(msg, "%s no dev\n", vol->vol_name);
1249 +         len = Mmsg(msg, "%s no device. released=%d\n", vol->vol_name, vol->released);
1250           sendit(msg.c_str(), len, arg);
1251        }
1252     }
1253 @@ -292,11 +292,11 @@
1254   *  already exist and are correctly programmed and will need no changes -- use 
1255   *  counts are always very tricky.
1256   *
1257 - *  The old code had a concept of "reserving" a Volume, but it needs to be changed 
1258 + *  The old code had a concept of "reserving" a Volume, but was changed 
1259   *  to reserving and using a drive.  A volume is must be attached to (owned by) a 
1260   *  drive and can move from drive to drive or be unused given certain specific 
1261   *  conditions of the drive.  The key is that the drive must "own" the Volume.  
1262 - *  The old code has the job (dcr) owning the volume (more or less).  The job is 
1263 + *  The old code had the job (dcr) owning the volume (more or less).  The job was
1264   *  to change the insertion and removal of the volumes from the list to be based 
1265   *  on the drive rather than the job.  
1266   *
1267 @@ -329,13 +329,14 @@
1268         *  because it was probably inserted by another job.
1269         */
1270        if (strcmp(vol->vol_name, VolumeName) == 0) {
1271 +         Dmsg1(dbglvl, "OK, vol=%s on device.\n", VolumeName);
1272           goto get_out;                  /* Volume already on this device */
1273        } else {
1274 -         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n", 
1275 +         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n",
1276                 (int)dcr->jcr->JobId, vol->vol_name, vol->vol_name);
1277 -         debug_list_volumes("reserve_vol free");
1278           vol_list->remove(vol);
1279           free_vol_item(vol);
1280 +         debug_list_volumes("reserve_vol free");
1281        }
1282     }
1283  
1284 @@ -378,12 +379,16 @@
1285              Dmsg4(dbglvl, "jid=%u Volume busy could not swap vol=%s from dev=%s to %s\n", 
1286                 jid(), VolumeName, vol->dev->print_name(), dev->print_name());
1287              vol = NULL;                /* device busy */
1288 +            goto get_out;
1289           }
1290        }
1291     }
1292     dev->vol = vol;
1293  
1294  get_out:
1295 +   if (vol) {
1296 +      vol->released = false;
1297 +   }
1298     debug_list_volumes("end new volume");
1299     unlock_volumes();
1300     return vol;
1301 @@ -462,6 +467,7 @@
1302      *  explicitly read in this drive. This allows the SD to remember
1303      *  where the tapes are or last were.
1304      */
1305 +   dev->vol->released = true;
1306     if (dev->is_tape() || dev->is_autochanger()) {
1307        return true;
1308     } else {
1309 @@ -837,6 +843,7 @@
1310        dlist *temp_vol_list, *save_vol_list;
1311        VOLRES *vol = NULL;
1312        lock_volumes();
1313 +      Dmsg0(dbglvl, "lock volumes\n");                           
1314  
1315        /*  
1316         * Create a temporary copy of the volume list.  We do this,
1317 @@ -1122,6 +1129,26 @@
1318               */
1319              if (dcr->volume_in_use && !rctx.PreferMountedVols) {
1320                 rctx.PreferMountedVols = true;
1321 +               if (dcr->VolumeName[0]) {
1322 +                  volume_unused(dcr);
1323 +               }
1324 +               goto bail_out;
1325 +            }
1326 +            /*
1327 +             * Note. Under some circumstances, the Director can hand us
1328 +             *  a Volume name that is no the same as the one on the current
1329 +             *  drive, and in that case, the call above to find the next
1330 +             *  volume will fail because in attempting to reserve the Volume
1331 +             *  the code will realize that we already have a tape mounted,
1332 +             *  and it will fail.  This *should* only happen if there are 
1333 +             *  writers, thus the following test.  In that case, we simply
1334 +             *  bail out, and continue waiting, rather than plunging on
1335 +             *  and hoping that the operator can resolve the problem. 
1336 +             */
1337 +            if (dcr->dev->num_writers != 0) {
1338 +               if (dcr->VolumeName[0]) {
1339 +                  volume_unused(dcr);
1340 +               }
1341                 goto bail_out;
1342              }
1343           }
1344 @@ -1270,6 +1297,51 @@
1345     return ok;
1346  }
1347  
1348 +static int is_pool_ok(DCR *dcr)
1349 +{
1350 +   DEVICE *dev = dcr->dev;
1351 +   JCR *jcr = dcr->jcr;
1352 +
1353 +   /* Now check if we want the same Pool and pool type */
1354 +   if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1355 +       strcmp(dev->pool_type, dcr->pool_type) == 0) {
1356 +      /* OK, compatible device */
1357 +      Dmsg1(dbglvl, "OK dev: %s num_writers=0, reserved, pool matches\n", dev->print_name());
1358 +      return 1;
1359 +   } else {
1360 +      /* Drive Pool not suitable for us */
1361 +      Mmsg(jcr->errmsg, _(
1362 +"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
1363 +            (uint32_t)jcr->JobId, dcr->pool_name, dev->pool_name,
1364 +            dev->reserved_device, dev->print_name());
1365 +      queue_reserve_message(jcr);
1366 +      Dmsg2(dbglvl, "failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
1367 +         dev->pool_name, dcr->pool_name);
1368 +   }
1369 +   return 0;
1370 +}
1371 +
1372 +static bool is_max_jobs_ok(DCR *dcr) 
1373 +{
1374 +   DEVICE *dev = dcr->dev;
1375 +   JCR *jcr = dcr->jcr;
1376 +
1377 +   Dmsg4(dbglvl, "MaxJobs=%d Jobs=%d reserves=%d Vol=%s\n",
1378 +         dcr->VolCatInfo.VolCatMaxJobs,
1379 +         dcr->VolCatInfo.VolCatJobs, dev->reserved_device,
1380 +         dcr->VolumeName);
1381 +   if (dcr->VolCatInfo.VolCatMaxJobs > 0 && dcr->VolCatInfo.VolCatMaxJobs <=
1382 +        (dcr->VolCatInfo.VolCatJobs + dev->reserved_device)) {
1383 +      /* Max Job Vols depassed or already reserved */
1384 +      Mmsg(jcr->errmsg, _("3610 JobId=%u Volume max jobs exceeded on drive %s.\n"), 
1385 +            (uint32_t)jcr->JobId, dev->print_name());
1386 +      queue_reserve_message(jcr);
1387 +      Dmsg1(dbglvl, "reserve dev failed: %s", jcr->errmsg);
1388 +      return false;                /* wait */
1389 +   }
1390 +   return true;
1391 +}
1392 +
1393  /*
1394   * Returns: 1 if drive can be reserved
1395   *          0 if we should wait
1396 @@ -1285,6 +1357,11 @@
1397           rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
1398           rctx.autochanger_only, rctx.any_drive);
1399  
1400 +   /* Check for max jobs on this Volume */
1401 +   if (!is_max_jobs_ok(dcr)) {
1402 +      return 0;
1403 +   }
1404 +
1405     /* setting any_drive overrides PreferMountedVols flag */
1406     if (!rctx.any_drive) {
1407        /*
1408 @@ -1374,32 +1451,10 @@
1409     if (dev->num_writers == 0) {
1410        /* Now check if there are any reservations on the drive */
1411        if (dev->reserved_device) {           
1412 -         /* Now check if we want the same Pool and pool type */
1413 -         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1414 -             strcmp(dev->pool_type, dcr->pool_type) == 0) {
1415 -            /* OK, compatible device */
1416 -            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, reserved, pool matches\n",
1417 -               jcr->JobId, dev->print_name());
1418 -            return 1;
1419 -         } else {
1420 -            /* Drive Pool not suitable for us */
1421 -            Mmsg(jcr->errmsg, _(
1422 -"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
1423 -                  jcr->JobId, dcr->pool_name, dev->pool_name,
1424 -                  dev->reserved_device, dev->print_name());
1425 -            queue_reserve_message(jcr);
1426 -            Dmsg3(dbglvl, "jid=%u failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
1427 -               (int)jcr->JobId, dev->pool_name, dcr->pool_name);
1428 -            return 0;                 /* wait */
1429 -         }
1430 +         return is_pool_ok(dcr);
1431        } else if (dev->can_append()) {
1432 -         /* Device in append mode, check if changing pool */
1433 -         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1434 -             strcmp(dev->pool_type, dcr->pool_type) == 0) {
1435 -            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, can_append, pool matches.\n",
1436 -               jcr->JobId, dev->print_name());
1437 -            /* OK, compatible device */
1438 -            return 1;
1439 +         if (is_pool_ok(dcr)) {
1440 +            return 1; 
1441           } else {
1442              /* Changing pool, unload old tape if any in drive */
1443              Dmsg1(dbglvl, "jid=%u OK dev: num_writers=0, not reserved, pool change, unload changer\n",
1444 @@ -1419,22 +1474,7 @@
1445      *  available if pool is the same).
1446      */
1447     if (dev->can_append() || dev->num_writers > 0) {
1448 -      /* Yes, now check if we want the same Pool and pool type */
1449 -      if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1450 -          strcmp(dev->pool_type, dcr->pool_type) == 0) {
1451 -         Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers>=0, can_append, pool matches.\n",
1452 -            jcr->JobId, dev->print_name());
1453 -         /* OK, compatible device */
1454 -         return 1;
1455 -      } else {
1456 -         /* Drive Pool not suitable for us */
1457 -         Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"), 
1458 -               jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name());
1459 -         queue_reserve_message(jcr);
1460 -         Dmsg3(dbglvl, "jid=%u failed: busy num_writers>0, can_append, pool=%s wanted=%s\n",
1461 -            (int)jcr->JobId, dev->pool_name, dcr->pool_name);
1462 -         return 0;                    /* wait */
1463 -      }
1464 +      return is_pool_ok(dcr);
1465     } else {
1466        Pmsg1(000, _("Logic error!!!! JobId=%u Should not get here.\n"), (int)jcr->JobId);
1467        Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"),