]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/ansi_label.c
kes Apply Eric's patch for recycling the Scratch pool.
[bacula/bacula] / bacula / src / stored / ansi_label.c
index 85fb30538daa35531a174ac0364fea829a5a78dd..a686d75b3c65b56ffa2c36cee50d2bbbc1a10885 100644 (file)
  *   Version $Id$
  */
 /*
-   Copyright (C) 2005 Kern Sibbald
+   Bacula® - The Network Backup Solution
 
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
+   Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
 
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
- */
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 
 #include "bacula.h"                   /* pull in global headers */
 #include "stored.h"                   /* pull in Storage Deamon headers */
 
+/* Imported functions */
+void ascii_to_ebcdic(char *dst, char *src, int count);
+void ebcdic_to_ascii(char *dst, char *src, int count);
+
 /* Forward referenced functions */
 static char *ansi_date(time_t td, char *buf);
 static bool same_label_names(char *bacula_name, char *ansi_name);
@@ -44,27 +56,28 @@ static bool same_label_names(char *bacula_name, char *ansi_name);
  * point, all is good.
  *
  * Returns:
- *    VOL_OK           Volume name OK
- *    VOL_NO_LABEL     No ANSI label on Volume
- *    VOL_IO_ERROR     I/O error on read
- *    VOL_NAME_ERROR   Wrong name in VOL1 record
- *    VOL_LABEL_ERROR  Probably an ANSI label, but something wrong
- *     
+ *    VOL_OK            Volume name OK
+ *    VOL_NO_LABEL      No ANSI label on Volume
+ *    VOL_IO_ERROR      I/O error on read
+ *    VOL_NAME_ERROR    Wrong name in VOL1 record
+ *    VOL_LABEL_ERROR   Probably an ANSI label, but something wrong
+ *      
  */ 
 int read_ansi_ibm_label(DCR *dcr) 
 {
    DEVICE *dev = dcr->dev;
    JCR *jcr = dcr->jcr;
-   char label[80];                   /* tape label */
+   char label[80];                    /* tape label */
    int stat, i;
    char *VolName = dcr->VolumeName;
+   bool ok = false;
 
    /*
     * Read VOL1, HDR1, HDR2 labels, but ignore the data
     *  If tape read the following EOF mark, on disk do
     *  not read.
     */
-   Dmsg0(000, "Read ansi label.\n");
+   Dmsg0(100, "Read ansi label.\n");
    if (!dev->is_tape()) {
       return VOL_OK;
    }
@@ -74,104 +87,192 @@ int read_ansi_ibm_label(DCR *dcr)
    /* Read a maximum of 5 records VOL1, HDR1, ... HDR4 */
    for (i=0; i < 6; i++) {
       do {
-        stat = read(dev->fd, label, sizeof(label));
+         stat = tape_read(dev->fd, label, sizeof(label));
       } while (stat == -1 && errno == EINTR);
       if (stat < 0) {
-        berrno be;
-        clrerror_dev(dev, -1);
-         Dmsg1(000, "Read device got: ERR=%s\n", be.strerror());
+         berrno be;
+         dev->clrerror(-1);
+         Dmsg1(100, "Read device got: ERR=%s\n", be.strerror());
          Mmsg2(jcr->errmsg, _("Read error on device %s in ANSI label. ERR=%s\n"),
-           dev->dev_name, be.strerror());
+            dev->dev_name, be.strerror());
          Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
-        dev->VolCatInfo.VolCatErrors++;
-        return VOL_IO_ERROR;
+         dev->VolCatInfo.VolCatErrors++;
+         return VOL_IO_ERROR;
       }
       if (stat == 0) {
-        if (dev->at_eof()) {
-           dev->state |= ST_EOT;
-            Dmsg0(000, "EOM on ANSI label\n");
+         if (dev->at_eof()) {
+            dev->set_eot();           /* second eof, set eot bit */
+            Dmsg0(100, "EOM on ANSI label\n");
             Mmsg0(jcr->errmsg, _("Insane! End of tape while reading ANSI label.\n"));
             return VOL_LABEL_ERROR;   /* at EOM this shouldn't happen */
-        } else {
-           dev->set_eof();
-        }
+         } else {
+            dev->set_ateof();        /* set eof state */
+         }
       }
       switch (i) {
-      case 0:                        /* Want VOL1 label */
-         if (stat != 80 || strncmp("VOL1", label, 4) != 0) {
-            Dmsg0(000, "No VOL1 label\n");
-            Mmsg0(jcr->errmsg, _("No VOL1 label while reading ANSI label.\n"));
-           return VOL_NO_LABEL;   /* No ANSI label */
-        }
+      case 0:                         /* Want VOL1 label */
+         if (stat == 80) {
+            if (strncmp("VOL1", label, 4) == 0) {
+               ok = true;
+               dev->label_type = B_ANSI_LABEL;
+            } else {
+               /* Try EBCDIC */
+               ebcdic_to_ascii(label, label, sizeof(label));
+               if (strncmp("VOL1", label, 4) == 0) {
+                  ok = true;;
+                  dev->label_type = B_IBM_LABEL;
+                  Dmsg0(100, "Found IBM label.\n");
+               }
+            }       
+         }
+         if (!ok) {
+            Dmsg0(100, "No VOL1 label\n");
+            Mmsg0(jcr->errmsg, _("No VOL1 label while reading ANSI/IBM label.\n"));
+            return VOL_NO_LABEL;   /* No ANSI label */
+         }
 
-        dev->label_type = B_ANSI_LABEL;
 
-        /* Compare Volume Names allow special wild card */
+         /* Compare Volume Names allow special wild card */
          if (VolName && *VolName && *VolName != '*') { 
-           if (!same_label_names(VolName, &label[4])) {
-              char *p = &label[4];
-              char *q = dev->VolHdr.VolName;
+            if (!same_label_names(VolName, &label[4])) {
+               char *p = &label[4];
+               char *q;  
+
+               free_volume(dev);
+               /* Store new Volume name */
+               q = dev->VolHdr.VolumeName;
                for (int i=0; *p != ' ' && i < 6; i++) {
-                 *q++ = *p++;
-              }
-              *q = 0;
-               Dmsg2(000, "Wanted ANSI Vol %s got %6s\n", VolName, dev->VolHdr.VolName);
-               Mmsg2(jcr->errmsg, "Wanted ANSI Volume \"%s\" got \"%s\"\n", VolName, dev->VolHdr.VolName);
-              return VOL_NAME_ERROR;
-           }
-        }
-        break;
+                  *q++ = *p++;
+               }
+               *q = 0;
+               new_volume(dcr, dev->VolHdr.VolumeName);
+               Dmsg2(100, "Wanted ANSI Vol %s got %6s\n", VolName, dev->VolHdr.VolumeName);
+               Mmsg2(jcr->errmsg, _("Wanted ANSI Volume \"%s\" got \"%s\"\n"), VolName, dev->VolHdr.VolumeName);
+               return VOL_NAME_ERROR;
+            }
+         }
+         break;
       case 1:
+         if (dev->label_type == B_IBM_LABEL) {
+            ebcdic_to_ascii(label, label, sizeof(label));
+         }
          if (stat != 80 || strncmp("HDR1", label, 4) != 0) {
-            Dmsg0(000, "No HDR1 label\n");
+            Dmsg0(100, "No HDR1 label\n");
             Mmsg0(jcr->errmsg, _("No HDR1 label while reading ANSI label.\n"));
-           return VOL_LABEL_ERROR;
-        }
+            return VOL_LABEL_ERROR;
+         }
          if (strncmp("BACULA.DATA", &label[4], 11) != 0) {
-            Dmsg1(000, "HD1 not Bacula label. Wanted  BACULA.DATA got %11s\n",
-              &label[4]);
-            Mmsg1(jcr->errmsg, _("ANSI Volume \"%s\" does not belong to Bacula.\n"),
-              dev->VolHdr.VolName);
-           return VOL_NAME_ERROR;     /* Not a Bacula label */
-        }
-        break;
+            Dmsg1(100, "HD1 not Bacula label. Wanted  BACULA.DATA got %11s\n",
+               &label[4]);
+            Mmsg1(jcr->errmsg, _("ANSI/IBM Volume \"%s\" does not belong to Bacula.\n"),
+               dev->VolHdr.VolumeName);
+            return VOL_NAME_ERROR;     /* Not a Bacula label */
+         }
+         break;
       case 2:
+         if (dev->label_type == B_IBM_LABEL) {
+            ebcdic_to_ascii(label, label, sizeof(label));
+         }
          if (stat != 80 || strncmp("HDR2", label, 4) != 0) {
-            Dmsg0(000, "No HDR2 label\n");
-            Mmsg0(jcr->errmsg, _("No HDR2 label while reading ANSI label.\n"));
-           return VOL_LABEL_ERROR;
-        }
-        break;
+            Dmsg0(100, "No HDR2 label\n");
+            Mmsg0(jcr->errmsg, _("No HDR2 label while reading ANSI/IBM label.\n"));
+            return VOL_LABEL_ERROR;
+         }
+         break;
       default:
-        if (stat == 0) {
-            Dmsg0(000, "ANSI label OK\n");
-           return VOL_OK;
-        }
+         if (stat == 0) {
+            Dmsg0(100, "ANSI label OK\n");
+            return VOL_OK;
+         }
+         if (dev->label_type == B_IBM_LABEL) {
+            ebcdic_to_ascii(label, label, sizeof(label));
+         }
          if (stat != 80 || strncmp("HDR", label, 3) != 0) {
-            Dmsg0(000, "Unknown or bad ANSI label record.\n");
-            Mmsg0(jcr->errmsg, _("Unknown or bad ANSI label record.\n"));
-           return VOL_LABEL_ERROR;
-        }
-        break;
+            Dmsg0(100, "Unknown or bad ANSI/IBM label record.\n");
+            Mmsg0(jcr->errmsg, _("Unknown or bad ANSI/IBM label record.\n"));
+            return VOL_LABEL_ERROR;
+         }
+         break;
       }
    }
-   Dmsg0(000, "Too many records in ANSI label.\n");
-   Mmsg0(jcr->errmsg, _("Too many records in while reading ANSI label.\n"));
+   Dmsg0(100, "Too many records in ANSI/IBM label.\n");
+   Mmsg0(jcr->errmsg, _("Too many records in while reading ANSI/IBM label.\n"));
    return VOL_LABEL_ERROR;
 }  
 
+/*
+ * ANSI/IBM VOL1 label
+ *  80 characters blank filled
+ * Pos   count   Function      What Bacula puts
+ * 0-3     4     "VOL1"          VOL1
+ * 4-9     6     Volume name     Volume name
+ * 10-10   1     Access code 
+ * 11-36   26    Unused
+ *
+ * ANSI
+ * 37-50   14    Owner
+ * 51-78   28    reserved
+ * 79       1    ANSI level        3
+ *
+ * IBM
+ * 37-40   4     reserved
+ * 41-50   10    Owner
+ * 51-79   29    reserved
+
+ *
+ *
+ * ANSI/IBM HDR1 label
+ *  80 characters blank filled
+ * Pos   count   Function          What Bacula puts
+ * 0-3     4     "HDR1"               HDR1
+ * 4-20    17    File name           BACULA.DATA
+ * 21-26   6     Volume name          Volume name
+ * 27-30   4     Vol seq num           0001
+ * 31-34   4     file num              0001
+ * 35-38   4     Generation            0001
+ * 39-40   2     Gen version           00
+ * 41-46   6     Create date bYYDDD    yesterday
+ * 47-52   6     Expire date bYYDDD    today
+ * 53-53   1     Access
+ * 54-59   6     Block count           000000
+ * 60-72   13    Software name         Bacula
+ * 73-79   7     Reserved
+
+ * ANSI/IBM HDR2 label
+ *  80 characters blank filled
+ * Pos   count   Function          What Bacula puts
+ * 0-3     4     "HDR2"               HDR2
+ * 4-4     1     Record format        D   (V if IBM) => variable
+ * 5-9     5     Block length         32000
+ * 10-14   5     Rec length           32000
+ * 15-15   1     Density
+ * 16-16   1     Continued 
+ * 17-33   17    Job
+ * 34-35   2     Recording
+ * 36-36   1     cr/lf ctl
+ * 37-37   1     reserved
+ * 38-38   1     Blocked flag
+ * 39-49   11    reserved
+ * 50-51   2     offset
+ * 52-79   28    reserved
+
+ */ 
+
+static const char *labels[] = {"HDR", "EOF", "EOV"};
+
 /*
  * Write an ANSI or IBM 80 character tape label
- *   Assume we are positioned at the beginning of the tape.
+ *   Type determines whether we are writing HDR, EOF, or EOV labels
+ *   Assume we are positioned to write the labels
  *   Returns:  true of OK
- *            false if error
+ *             false if error
  */
-bool write_ansi_ibm_label(DCR *dcr, const char *VolName)
+bool write_ansi_ibm_labels(DCR *dcr, int type, const char *VolName)
 {
    DEVICE *dev = dcr->dev;
    JCR *jcr = dcr->jcr;
-   char label[80];                   /* tape label */
-   char date[20];                    /* ansi date buffer */
+   char label[80];                    /* tape label */
+   char date[20];                     /* ansi date buffer */
    time_t now;
    int len, stat, label_type;
 
@@ -191,32 +292,40 @@ bool write_ansi_ibm_label(DCR *dcr, const char *VolName)
    case B_ANSI_LABEL:
    case B_IBM_LABEL:
       ser_declare;
-      Dmsg1(000, "Write ANSI label type=%d\n", label_type);
+      Dmsg1(100, "Write ANSI label type=%d\n", label_type);
       len = strlen(VolName);
       if (len > 6) {
          Jmsg1(jcr, M_FATAL, 0, _("ANSI Volume label name \"%s\" longer than 6 chars.\n"),
-           VolName);
-        return false;
+            VolName);
+         return false;
       }
-      memset(label, ' ', sizeof(label));
-      ser_begin(label, sizeof(label));
-      ser_bytes("VOL1", 4);
-      ser_bytes(VolName, len);
-      label[79] = '3';                /* ANSI label flag */
-      /* Write VOL1 label */
-      stat = write(dev->fd, label, sizeof(label));
-      if (stat != sizeof(label)) {
-        berrno be;
-         Jmsg1(jcr, M_FATAL, 0,  _("Could not write ANSI VOL1 label. ERR=%s\n"),
-           be.strerror());
-        return false;
+      if (type == ANSI_VOL_LABEL) {
+         ser_begin(label, sizeof(label));
+         ser_bytes("VOL1", 4);
+         ser_bytes(VolName, len);
+         /* Write VOL1 label */
+         if (label_type == B_IBM_LABEL) {
+            ascii_to_ebcdic(label, label, sizeof(label));
+         } else {
+            label[79] = '3';                /* ANSI label flag */
+         }
+         stat = tape_write(dev->fd, label, sizeof(label));
+         if (stat != sizeof(label)) {
+            berrno be;
+            Jmsg1(jcr, M_FATAL, 0,  _("Could not write ANSI VOL1 label. ERR=%s\n"),
+               be.strerror());
+            return false;
+         }
       }
+
       /* Now construct HDR1 label */
+      memset(label, ' ', sizeof(label));
       ser_begin(label, sizeof(label));
-      ser_bytes("HDR1", 4);
+      ser_bytes(labels[type], 3);
+      ser_bytes("1", 1);
       ser_bytes("BACULA.DATA", 11);            /* Filename field */
       ser_begin(&label[21], sizeof(label)-21); /* fileset field */
-      ser_bytes(VolName, len);       /* write Vol Ser No. */
+      ser_bytes(VolName, len);        /* write Vol Ser No. */
       ser_begin(&label[27], sizeof(label)-27);
       ser_bytes("00010001000100", 14);  /* File section, File seq no, Generation no */
       now = time(NULL);
@@ -224,28 +333,66 @@ bool write_ansi_ibm_label(DCR *dcr, const char *VolName)
       ser_bytes(ansi_date(now - 24 * 3600, date), 6); /* created yesterday */
       ser_bytes(" 000000Bacula              ", 27);
       /* Write HDR1 label */
-      stat = write(dev->fd, label, sizeof(label));
+      if (label_type == B_IBM_LABEL) {
+         ascii_to_ebcdic(label, label, sizeof(label));
+      }
+
+      /*
+       * This could come at the end of a tape, ignore
+       *  EOT errors.
+       */
+      stat = tape_write(dev->fd, label, sizeof(label));
       if (stat != sizeof(label)) {
-        berrno be;
-         Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
-           be.strerror());
-        return false;
+         berrno be;
+         if (stat == -1) {
+            dev->clrerror(-1);
+            if (dev->dev_errno == 0) {
+               dev->dev_errno = ENOSPC; /* out of space */
+            }
+            if (dev->dev_errno != ENOSPC) {
+               Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
+               be.strerror());
+               return false;
+            }
+         } else {
+            Jmsg(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label.\n"));
+            return false;
+         }
       }
+
       /* Now construct HDR2 label */
       memset(label, ' ', sizeof(label));
       ser_begin(label, sizeof(label));
-      ser_bytes("HDR2F3200032000", 15);
-      /* Write HDR1 label */
-      stat = write(dev->fd, label, sizeof(label));
+      ser_bytes(labels[type], 3);
+      ser_bytes("2D3200032000", 12);
+      /* Write HDR2 label */
+      if (label_type == B_IBM_LABEL) {
+         label[4] = 'V';
+         ascii_to_ebcdic(label, label, sizeof(label));
+      }
+      stat = tape_write(dev->fd, label, sizeof(label));
       if (stat != sizeof(label)) {
-        berrno be;
-         Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
-           be.strerror());
-        return false;
+         berrno be;
+         if (stat == -1) {
+            dev->clrerror(-1);
+            if (dev->dev_errno == 0) {
+               dev->dev_errno = ENOSPC; /* out of space */
+            }
+            if (dev->dev_errno != ENOSPC) {
+               Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
+               be.strerror());
+               return false;
+            }
+            dev->weof(1);
+            return true;
+         } else {
+            Jmsg(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label.\n"));
+            return false;
+         }
       }
-      if (weof_dev(dev, 1) < 0) {
+      if (!dev->weof(1)) {
          Jmsg(jcr, M_FATAL, 0, _("Error writing EOF to tape. ERR=%s"), dev->errmsg);
-        return false;
+         return false;
       }
       return true;
    default:
@@ -262,13 +409,13 @@ static bool same_label_names(char *bacula_name, char *ansi_name)
    /* Six characters max */
    for (int i=0; i < 6; i++) {
       if (*a == *b) {
-        a++;
-        b++;
-        continue;
+         a++;
+         b++;
+         continue;
       }
       /* ANSI labels are blank filled, Bacula's are zero terminated */
       if (*a == ' ' && *b == 0) {
-        return true;
+         return true;
       }
       return false;
    }
@@ -280,7 +427,10 @@ static bool same_label_names(char *bacula_name, char *ansi_name)
    return false;
 }
 
-
+/*
+ * ANSI date
+ *  ' 'YYDDD
+ */
 static char *ansi_date(time_t td, char *buf)
 {
    struct tm *tm;