]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/ansi_label.c
0ee7ad0f8a63addc4cdf25ecb02de71629c70f0a
[bacula/bacula] / bacula / src / stored / ansi_label.c
1 /*
2  *
3  *  ansi_label.c routines to handle ANSI (and perhaps one day IBM)
4  *   tape labels.
5  *
6  *   Kern Sibbald, MMV
7  *
8  *
9  *
10  *   Version $Id$
11  */
12 /*
13    Copyright (C) 2005 Kern Sibbald
14
15    This program is free software; you can redistribute it and/or
16    modify it under the terms of the GNU General Public License as
17    published by the Free Software Foundation; either version 2 of
18    the License, or (at your option) any later version.
19
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU General Public
26    License along with this program; if not, write to the Free
27    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28    MA 02111-1307, USA.
29
30  */
31
32 #include "bacula.h"                   /* pull in global headers */
33 #include "stored.h"                   /* pull in Storage Deamon headers */
34
35 /* Forward referenced functions */
36 static char *ansi_date(time_t td, char *buf);
37 static bool same_label_names(char *bacula_name, char *ansi_name);
38
39 /*
40  * We read an ANSI label and compare the Volume name. We require
41  * a VOL1 record of 80 characters followed by a HDR1 record containing
42  * BACULA.DATA in the filename field. We then read up to 3 more 
43  * header records (they are not required) and an EOF, at which
44  * point, all is good.
45  *
46  * Returns:
47  *    VOL_OK            Volume name OK
48  *    VOL_NO_LABEL      No ANSI label on Volume
49  *    VOL_IO_ERROR      I/O error on read
50  *    VOL_NAME_ERROR    Wrong name in VOL1 record
51  *    VOL_LABEL_ERROR   Probably an ANSI label, but something wrong
52  *      
53  */ 
54 int read_ansi_ibm_label(DCR *dcr) 
55 {
56    DEVICE *dev = dcr->dev;
57    JCR *jcr = dcr->jcr;
58    char label[80];                    /* tape label */
59    int stat, i;
60    char *VolName = dcr->VolumeName;
61
62    /*
63     * Read VOL1, HDR1, HDR2 labels, but ignore the data
64     *  If tape read the following EOF mark, on disk do
65     *  not read.
66     */
67    Dmsg0(000, "Read ansi label.\n");
68    if (!dev->is_tape()) {
69       return VOL_OK;
70    }
71
72    dev->label_type = B_BACULA_LABEL;  /* assume Bacula label */
73
74    /* Read a maximum of 5 records VOL1, HDR1, ... HDR4 */
75    for (i=0; i < 6; i++) {
76       do {
77          stat = read(dev->fd, label, sizeof(label));
78       } while (stat == -1 && errno == EINTR);
79       if (stat < 0) {
80          berrno be;
81          clrerror_dev(dev, -1);
82          Dmsg1(000, "Read device got: ERR=%s\n", be.strerror());
83          Mmsg2(dev->errmsg, _("Read error on device %s in ANSI/IBM label. ERR=%s\n"),
84             dev->dev_name, be.strerror());
85          Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
86          dev->VolCatInfo.VolCatErrors++;
87          return VOL_IO_ERROR;
88       }
89       if (stat == 0) {
90          if (dev->at_eof()) {
91             dev->state |= ST_EOT;
92             Dmsg0(000, "EOM on ANSI label\n");
93             return VOL_LABEL_ERROR;   /* at EOM this shouldn't happen */
94          } else {
95             dev->set_eof();
96          }
97       }
98       switch (i) {
99       case 0:                         /* Want VOL1 label */
100          if (stat != 80 || strncmp("VOL1", label, 4) != 0) {
101             Dmsg0(000, "No VOL1 label\n");
102             return VOL_NO_LABEL;   /* No ANSI label */
103          }
104
105          dev->label_type = B_ANSI_LABEL;
106
107          /* Compare Volume Names allow special wild card */
108          if (VolName && *VolName && *VolName != '*') { 
109             if (!same_label_names(VolName, &label[4])) {
110                char *p = &label[4];
111                char *q = dev->VolHdr.VolName;
112                for (int i=0; *p != ' ' && i < 6; i++) {
113                   *q++ = *p++;
114                }
115                *q = 0;
116                Dmsg2(000, "Wanted ANSI Vol %s got %6s\n", VolName, dev->VolHdr.VolName);
117                return VOL_NAME_ERROR;
118             }
119          }
120          break;
121       case 1:
122          if (stat != 80 || strncmp("HDR1", label, 4) != 0) {
123             Dmsg0(000, "No HDR1 label\n");
124             return VOL_LABEL_ERROR;
125          }
126          if (strncmp("BACULA.DATA", &label[4], 11) != 0) {
127             Dmsg1(000, "HD1 not Bacula label. Wanted  BACULA.DATA got %11s\n",
128                &label[4]);
129             return VOL_NAME_ERROR;     /* Not a Bacula label */
130          }
131          break;
132       case 2:
133          if (stat != 80 || strncmp("HDR2", label, 4) != 0) {
134             Dmsg0(000, "No HDR2 label\n");
135             return VOL_LABEL_ERROR;
136          }
137          break;
138       default:
139          if (stat == 0) {
140             Dmsg0(000, "ANSI label OK\n");
141             return VOL_OK;
142          }
143          if (stat != 80 || strncmp("HDR", label, 3) != 0) {
144             Dmsg0(000, "Unknown or bad ANSI label record.\n");
145             return VOL_LABEL_ERROR;
146          }
147          break;
148       }
149    }
150    Dmsg0(000, "Too many records in ANSI label.\n");
151    return VOL_LABEL_ERROR;
152 }  
153
154 /*
155  * Write an ANSI or IBM 80 character tape label
156  *   Assume we are positioned at the beginning of the tape.
157  *   Returns:  true of OK
158  *             false if error
159  */
160 bool write_ansi_ibm_label(DCR *dcr, const char *VolName)
161 {
162    DEVICE *dev = dcr->dev;
163    JCR *jcr = dcr->jcr;
164    char label[80];                    /* tape label */
165    char date[20];                     /* ansi date buffer */
166    time_t now;
167    int len, stat, label_type;
168
169    /*
170     * If the Device requires a specific label type use it,
171     * otherwise, use the type requested by the Director
172     */
173    if (dcr->device->label_type != B_BACULA_LABEL) {
174       label_type = dcr->device->label_type;   /* force label type */
175    } else {
176       label_type = dcr->VolCatInfo.LabelType; /* accept Dir type */
177    }
178
179    switch (label_type) {
180    case B_BACULA_LABEL:
181       return true;
182    case B_ANSI_LABEL:
183    case B_IBM_LABEL:
184       ser_declare;
185       Dmsg1(000, "Write ANSI label type=%d\n", label_type);
186       len = strlen(VolName);
187       if (len > 6) {
188          Jmsg1(jcr, M_FATAL, 0, _("ANSI Volume label name \"%s\" longer than 6 chars.\n"),
189             VolName);
190          return false;
191       }
192       memset(label, ' ', sizeof(label));
193       ser_begin(label, sizeof(label));
194       ser_bytes("VOL1", 4);
195       ser_bytes(VolName, len);
196       label[79] = '3';                /* ANSI label flag */
197       /* Write VOL1 label */
198       stat = write(dev->fd, label, sizeof(label));
199       if (stat != sizeof(label)) {
200          berrno be;
201          Jmsg1(jcr, M_FATAL, 0,  _("Could not write ANSI VOL1 label. ERR=%s\n"),
202             be.strerror());
203          return false;
204       }
205       /* Now construct HDR1 label */
206       ser_begin(label, sizeof(label));
207       ser_bytes("HDR1", 4);
208       ser_bytes("BACULA.DATA", 11);            /* Filename field */
209       ser_begin(&label[21], sizeof(label)-21); /* fileset field */
210       ser_bytes(VolName, len);        /* write Vol Ser No. */
211       ser_begin(&label[27], sizeof(label)-27);
212       ser_bytes("00010001000100", 14);  /* File section, File seq no, Generation no */
213       now = time(NULL);
214       ser_bytes(ansi_date(now, date), 6); /* current date */
215       ser_bytes(ansi_date(now - 24 * 3600, date), 6); /* created yesterday */
216       ser_bytes(" 000000Bacula              ", 27);
217       /* Write HDR1 label */
218       stat = write(dev->fd, label, sizeof(label));
219       if (stat != sizeof(label)) {
220          berrno be;
221          Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
222             be.strerror());
223          return false;
224       }
225       /* Now construct HDR2 label */
226       memset(label, ' ', sizeof(label));
227       ser_begin(label, sizeof(label));
228       ser_bytes("HDR2F3200032000", 15);
229       /* Write HDR1 label */
230       stat = write(dev->fd, label, sizeof(label));
231       if (stat != sizeof(label)) {
232          berrno be;
233          Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
234             be.strerror());
235          return false;
236       }
237       if (weof_dev(dev, 1) < 0) {
238          Jmsg(jcr, M_FATAL, 0, _("Error writing EOF to tape. ERR=%s"), dev->errmsg);
239          return false;
240       }
241       return true;
242    default:
243       Jmsg0(jcr, M_ABORT, 0, _("write_ansi_ibm_label called for non-ANSI/IBM type\n"));
244       return false; /* should not get here */
245    }
246 }
247
248 /* Check a Bacula Volume name against an ANSI Volume name */
249 static bool same_label_names(char *bacula_name, char *ansi_name)
250 {
251    char *a = ansi_name;
252    char *b = bacula_name;
253    /* Six characters max */
254    for (int i=0; i < 6; i++) {
255       if (*a == *b) {
256          a++;
257          b++;
258          continue;
259       }
260       /* ANSI labels are blank filled, Bacula's are zero terminated */
261       if (*a == ' ' && *b == 0) {
262          return true;
263       }
264       return false;
265    }
266    /* Reached 6 characters */
267    b++;
268    if (*b == 0) {
269       return true;
270    }
271    return false;
272 }
273
274
275 static char *ansi_date(time_t td, char *buf)
276 {
277    struct tm *tm;
278
279    if (td == 0) {
280       td = time(NULL);
281    }
282    tm = gmtime(&td);
283    bsnprintf(buf, 10, " %05d ", 1000 * (tm->tm_year + 1900 - 2000) + tm->tm_yday);
284    return buf;
285 }