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