]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/ansi_label.c
- Add code to ensure that reserved but unused volumes
[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
17    version 2 as ammended with additional clauses defined in the
18    file LICENSE in the main source directory.
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 
23    the file LICENSE for additional details.
24
25  */
26
27 #include "bacula.h"                   /* pull in global headers */
28 #include "stored.h"                   /* pull in Storage Deamon headers */
29
30 /* Imported functions */
31 void ascii_to_ebcdic(char *dst, char *src, int count);
32 void ebcdic_to_ascii(char *dst, char *src, int count);
33
34 /* Forward referenced functions */
35 static char *ansi_date(time_t td, char *buf);
36 static bool same_label_names(char *bacula_name, char *ansi_name);
37
38 /*
39  * We read an ANSI label and compare the Volume name. We require
40  * a VOL1 record of 80 characters followed by a HDR1 record containing
41  * BACULA.DATA in the filename field. We then read up to 3 more 
42  * header records (they are not required) and an EOF, at which
43  * point, all is good.
44  *
45  * Returns:
46  *    VOL_OK            Volume name OK
47  *    VOL_NO_LABEL      No ANSI label on Volume
48  *    VOL_IO_ERROR      I/O error on read
49  *    VOL_NAME_ERROR    Wrong name in VOL1 record
50  *    VOL_LABEL_ERROR   Probably an ANSI label, but something wrong
51  *      
52  */ 
53 int read_ansi_ibm_label(DCR *dcr) 
54 {
55    DEVICE *dev = dcr->dev;
56    JCR *jcr = dcr->jcr;
57    char label[80];                    /* tape label */
58    int stat, i;
59    char *VolName = dcr->VolumeName;
60    bool ok = false;
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(100, "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(100, "Read device got: ERR=%s\n", be.strerror());
83          Mmsg2(jcr->errmsg, _("Read error on device %s in ANSI 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->set_eot();           /* second eof, set eot bit */
92             Dmsg0(100, "EOM on ANSI label\n");
93             Mmsg0(jcr->errmsg, _("Insane! End of tape while reading ANSI label.\n"));
94             return VOL_LABEL_ERROR;   /* at EOM this shouldn't happen */
95          } else {
96             dev->set_ateof();        /* set eof state */
97          }
98       }
99       switch (i) {
100       case 0:                         /* Want VOL1 label */
101          if (stat == 80) {
102             if (strncmp("VOL1", label, 4) == 0) {
103                ok = true;
104                dev->label_type = B_ANSI_LABEL;
105             } else {
106                /* Try EBCDIC */
107                ebcdic_to_ascii(label, label, sizeof(label));
108                if (strncmp("VOL1", label, 4) == 0) {
109                   ok = true;;
110                   dev->label_type = B_IBM_LABEL;
111                }
112             }       
113          }
114          if (!ok) {
115             Dmsg0(100, "No VOL1 label\n");
116             Mmsg0(jcr->errmsg, _("No VOL1 label while reading ANSI/IBM label.\n"));
117             return VOL_NO_LABEL;   /* No ANSI label */
118          }
119
120
121          /* Compare Volume Names allow special wild card */
122          if (VolName && *VolName && *VolName != '*') { 
123             if (!same_label_names(VolName, &label[4])) {
124                char *p = &label[4];
125                char *q = dev->VolHdr.VolumeName;
126                for (int i=0; *p != ' ' && i < 6; i++) {
127                   *q++ = *p++;
128                }
129                *q = 0;
130                new_volume(dcr, dev->VolHdr.VolumeName);
131                Dmsg2(100, "Wanted ANSI Vol %s got %6s\n", VolName, dev->VolHdr.VolumeName);
132                Mmsg2(jcr->errmsg, "Wanted ANSI Volume \"%s\" got \"%s\"\n", VolName, dev->VolHdr.VolumeName);
133                return VOL_NAME_ERROR;
134             }
135          }
136          break;
137       case 1:
138          if (dev->label_type == B_IBM_LABEL) {
139             ebcdic_to_ascii(label, label, sizeof(label));
140          }
141          if (stat != 80 || strncmp("HDR1", label, 4) != 0) {
142             Dmsg0(100, "No HDR1 label\n");
143             Mmsg0(jcr->errmsg, _("No HDR1 label while reading ANSI label.\n"));
144             return VOL_LABEL_ERROR;
145          }
146          if (strncmp("BACULA.DATA", &label[4], 11) != 0) {
147             Dmsg1(100, "HD1 not Bacula label. Wanted  BACULA.DATA got %11s\n",
148                &label[4]);
149             Mmsg1(jcr->errmsg, _("ANSI/IBM Volume \"%s\" does not belong to Bacula.\n"),
150                dev->VolHdr.VolumeName);
151             return VOL_NAME_ERROR;     /* Not a Bacula label */
152          }
153          break;
154       case 2:
155          if (dev->label_type == B_IBM_LABEL) {
156             ebcdic_to_ascii(label, label, sizeof(label));
157          }
158          if (stat != 80 || strncmp("HDR2", label, 4) != 0) {
159             Dmsg0(100, "No HDR2 label\n");
160             Mmsg0(jcr->errmsg, _("No HDR2 label while reading ANSI/IBM label.\n"));
161             return VOL_LABEL_ERROR;
162          }
163          break;
164       default:
165          if (stat == 0) {
166             Dmsg0(100, "ANSI label OK\n");
167             return VOL_OK;
168          }
169          if (dev->label_type == B_IBM_LABEL) {
170             ebcdic_to_ascii(label, label, sizeof(label));
171          }
172          if (stat != 80 || strncmp("HDR", label, 3) != 0) {
173             Dmsg0(100, "Unknown or bad ANSI/IBM label record.\n");
174             Mmsg0(jcr->errmsg, _("Unknown or bad ANSI/IBM label record.\n"));
175             return VOL_LABEL_ERROR;
176          }
177          break;
178       }
179    }
180    Dmsg0(100, "Too many records in ANSI/IBM label.\n");
181    Mmsg0(jcr->errmsg, _("Too many records in while reading ANSI/IBM label.\n"));
182    return VOL_LABEL_ERROR;
183 }  
184
185 /*
186  * ANSI/IBM VOL1 label
187  *  80 characters blank filled
188  * Pos   count   Function      What Bacula puts
189  * 0-3     4     "VOL1"          VOL1
190  * 4-9     6     Volume name     Volume name
191  * 10-10   1     Access code 
192  * 11-36   26    Unused
193  *
194  * ANSI
195  * 37-50   14    Owner
196  * 51-78   28    reserved
197  * 79       1    ANSI level        3
198  *
199  * IBM
200  * 37-40   4     reserved
201  * 41-50   10    Owner
202  * 51-79   29    reserved
203
204  *
205  *
206  * ANSI/IBM HDR1 label
207  *  80 characters blank filled
208  * Pos   count   Function          What Bacula puts
209  * 0-3     4     "HDR1"               HDR1
210  * 4-20    17    File name           BACULA.DATA
211  * 21-26   6     Volume name          Volume name
212  * 27-30   4     Vol seq num           0001
213  * 31-34   4     file num              0001
214  * 35-38   4     Generation            0001
215  * 39-40   2     Gen version           00
216  * 41-46   6     Create date bYYDDD    yesterday
217  * 47-52   6     Expire date bYYDDD    today
218  * 53-53   1     Access
219  * 54-59   6     Block count           000000
220  * 60-72   13    Software name         Bacula
221  * 73-79   7     Reserved
222
223  * ANSI/IBM HDR2 label
224  *  80 characters blank filled
225  * Pos   count   Function          What Bacula puts
226  * 0-3     4     "HDR2"               HDR2
227  * 4-4     1     Record format        D   (V if IBM) => variable
228  * 5-9     5     Block length         32000
229  * 10-14   5     Rec length           32000
230  * 15-15   1     Density
231  * 16-16   1     Continued 
232  * 17-33   17    Job
233  * 34-35   2     Recording
234  * 36-36   1     cr/lf ctl
235  * 37-37   1     reserved
236  * 38-38   1     Blocked flag
237  * 39-49   11    reserved
238  * 50-51   2     offset
239  * 52-79   28    reserved
240
241  */ 
242
243 static const char *labels[] = {"HDR", "EOF", "EOV"};
244
245 /*
246  * Write an ANSI or IBM 80 character tape label
247  *   Type determines whether we are writing HDR, EOF, or EOV labels
248  *   Assume we are positioned to write the labels
249  *   Returns:  true of OK
250  *             false if error
251  */
252 bool write_ansi_ibm_labels(DCR *dcr, int type, const char *VolName)
253 {
254    DEVICE *dev = dcr->dev;
255    JCR *jcr = dcr->jcr;
256    char label[80];                    /* tape label */
257    char date[20];                     /* ansi date buffer */
258    time_t now;
259    int len, stat, label_type;
260
261    /*
262     * If the Device requires a specific label type use it,
263     * otherwise, use the type requested by the Director
264     */
265    if (dcr->device->label_type != B_BACULA_LABEL) {
266       label_type = dcr->device->label_type;   /* force label type */
267    } else {
268       label_type = dcr->VolCatInfo.LabelType; /* accept Dir type */
269    }
270
271    switch (label_type) {
272    case B_BACULA_LABEL:
273       return true;
274    case B_ANSI_LABEL:
275    case B_IBM_LABEL:
276       ser_declare;
277       Dmsg1(100, "Write ANSI label type=%d\n", label_type);
278       len = strlen(VolName);
279       if (len > 6) {
280          Jmsg1(jcr, M_FATAL, 0, _("ANSI Volume label name \"%s\" longer than 6 chars.\n"),
281             VolName);
282          return false;
283       }
284       if (type == ANSI_VOL_LABEL) {
285          ser_begin(label, sizeof(label));
286          ser_bytes("VOL1", 4);
287          ser_bytes(VolName, len);
288          /* Write VOL1 label */
289          if (label_type == B_IBM_LABEL) {
290             ascii_to_ebcdic(label, label, sizeof(label));
291          } else {
292             label[79] = '3';                /* ANSI label flag */
293          }
294          stat = write(dev->fd, label, sizeof(label));
295          if (stat != sizeof(label)) {
296             berrno be;
297             Jmsg1(jcr, M_FATAL, 0,  _("Could not write ANSI VOL1 label. ERR=%s\n"),
298                be.strerror());
299             return false;
300          }
301       }
302
303       /* Now construct HDR1 label */
304       memset(label, ' ', sizeof(label));
305       ser_begin(label, sizeof(label));
306       ser_bytes(labels[type], 3);
307       ser_bytes("1", 1);
308       ser_bytes("BACULA.DATA", 11);            /* Filename field */
309       ser_begin(&label[21], sizeof(label)-21); /* fileset field */
310       ser_bytes(VolName, len);        /* write Vol Ser No. */
311       ser_begin(&label[27], sizeof(label)-27);
312       ser_bytes("00010001000100", 14);  /* File section, File seq no, Generation no */
313       now = time(NULL);
314       ser_bytes(ansi_date(now, date), 6); /* current date */
315       ser_bytes(ansi_date(now - 24 * 3600, date), 6); /* created yesterday */
316       ser_bytes(" 000000Bacula              ", 27);
317       /* Write HDR1 label */
318       if (label_type == B_IBM_LABEL) {
319          ascii_to_ebcdic(label, label, sizeof(label));
320       }
321       stat = write(dev->fd, label, sizeof(label));
322       if (stat != sizeof(label)) {
323          berrno be;
324          Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
325             be.strerror());
326          return false;
327       }
328
329
330       /* Now construct HDR2 label */
331       memset(label, ' ', sizeof(label));
332       ser_begin(label, sizeof(label));
333       ser_bytes(labels[type], 3);
334       ser_bytes("2D3200032000", 12);
335       /* Write HDR2 label */
336       if (label_type == B_IBM_LABEL) {
337          label[4] = 'V';
338          ascii_to_ebcdic(label, label, sizeof(label));
339       }
340       stat = write(dev->fd, label, sizeof(label));
341       if (stat != sizeof(label)) {
342          berrno be;
343          Jmsg1(jcr, M_FATAL, 0, _("Could not write ANSI HDR1 label. ERR=%s\n"),
344             be.strerror());
345          return false;
346       }
347       if (weof_dev(dev, 1) < 0) {
348          Jmsg(jcr, M_FATAL, 0, _("Error writing EOF to tape. ERR=%s"), dev->errmsg);
349          return false;
350       }
351       return true;
352    default:
353       Jmsg0(jcr, M_ABORT, 0, _("write_ansi_ibm_label called for non-ANSI/IBM type\n"));
354       return false; /* should not get here */
355    }
356 }
357
358 /* Check a Bacula Volume name against an ANSI Volume name */
359 static bool same_label_names(char *bacula_name, char *ansi_name)
360 {
361    char *a = ansi_name;
362    char *b = bacula_name;
363    /* Six characters max */
364    for (int i=0; i < 6; i++) {
365       if (*a == *b) {
366          a++;
367          b++;
368          continue;
369       }
370       /* ANSI labels are blank filled, Bacula's are zero terminated */
371       if (*a == ' ' && *b == 0) {
372          return true;
373       }
374       return false;
375    }
376    /* Reached 6 characters */
377    b++;
378    if (*b == 0) {
379       return true;
380    }
381    return false;
382 }
383
384 /*
385  * ANSI date
386  *  ' 'YYDDD
387  */
388 static char *ansi_date(time_t td, char *buf)
389 {
390    struct tm *tm;
391
392    if (td == 0) {
393       td = time(NULL);
394    }
395    tm = gmtime(&td);
396    bsnprintf(buf, 10, " %05d ", 1000 * (tm->tm_year + 1900 - 2000) + tm->tm_yday);
397    return buf;
398 }