928a37c04fa2aba2461a143379a3b5a773942eeb
[debian/amanda] / common-src / fileheader.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: fileheader.c,v 1.11.4.1.4.1.2.6 2003/10/24 13:44:49 martinea Exp $
28  *
29  */
30
31 #include "amanda.h"
32 #include "fileheader.h"
33
34
35 void fh_init(file)
36 dumpfile_t *file;
37 {
38     memset(file,'\0',sizeof(*file));
39     file->blocksize = DISK_BLOCK_BYTES;
40 }
41
42
43 void
44 parse_file_header(buffer, file, buflen)
45     char *buffer;
46     dumpfile_t *file;
47     size_t buflen;
48 {
49     string_t line, save_line;
50     char *bp, *str, *ptr_buf, *start_buf;
51     int nchars;
52     char *verify;
53     char *s, *s1, *s2;
54     int ch;
55     int done;
56
57     /* isolate first line */
58
59     nchars = buflen<sizeof(line)? buflen : sizeof(line) - 1;
60     for(s=line, ptr_buf=buffer; ptr_buf < buffer+nchars; ptr_buf++, s++) {
61         ch = *ptr_buf;
62         if(ch == '\n') {
63             *s = '\0';
64             break;
65         }
66         *s = ch;
67     }
68     line[sizeof(line)-1] = '\0';
69     strncpy(save_line, line, sizeof(save_line));
70
71     fh_init(file); 
72     s = line;
73     ch = *s++;
74
75     skip_whitespace(s, ch);
76     str = s - 1;
77     skip_non_whitespace(s, ch);
78     s[-1] = '\0';
79
80     if(strcmp(str, "NETDUMP:") != 0 && strcmp(str,"AMANDA:") != 0) {
81         file->type = F_UNKNOWN;
82         return;
83     }
84
85     skip_whitespace(s, ch);
86     if(ch == '\0') {
87         goto weird_header;
88     }
89     str = s - 1;
90     skip_non_whitespace(s, ch);
91     s[-1] = '\0';
92
93     if(strcmp(str, "TAPESTART") == 0) {
94         file->type = F_TAPESTART;
95
96         skip_whitespace(s, ch);
97         if(ch == '\0') {
98             goto weird_header;
99         }
100         verify = s - 1;
101         skip_non_whitespace(s, ch);
102         s[-1] = '\0';
103         if(strcmp(verify, "DATE") != 0) {
104             goto weird_header;
105         }
106
107         skip_whitespace(s, ch);
108         if(ch == '\0') {
109             goto weird_header;
110         }
111         copy_string(s, ch, file->datestamp, sizeof(file->datestamp), bp);
112         if(bp == NULL) {
113             goto weird_header;
114         }
115
116         skip_whitespace(s, ch);
117         if(ch == '\0') {
118             goto weird_header;
119         }
120         verify = s - 1;
121         skip_non_whitespace(s, ch);
122         s[-1] = '\0';
123         if(strcmp(verify, "TAPE") != 0) {
124             goto weird_header;
125         }
126
127         skip_whitespace(s, ch);
128         if(ch == '\0') {
129             goto weird_header;
130         }
131         copy_string(s, ch, file->name, sizeof(file->name), bp);
132         if(bp == NULL) {
133             goto weird_header;
134         }
135     } else if(strcmp(str, "FILE") == 0 || 
136               strcmp(str, "CONT_FILE") == 0) {
137         if(strcmp(str, "FILE") == 0)
138             file->type = F_DUMPFILE;
139         else if(strcmp(str, "CONT_FILE") == 0)
140             file->type = F_CONT_DUMPFILE;
141
142         skip_whitespace(s, ch);
143         if(ch == '\0') {
144             goto weird_header;
145         }
146         copy_string(s, ch, file->datestamp, sizeof(file->datestamp), bp);
147         if(bp == NULL) {
148             goto weird_header;
149         }
150
151         skip_whitespace(s, ch);
152         if(ch == '\0') {
153             goto weird_header;
154         }
155         copy_string(s, ch, file->name, sizeof(file->name), bp);
156         if(bp == NULL) {
157             goto weird_header;
158         }
159
160         skip_whitespace(s, ch);
161         if(ch == '\0') {
162             goto weird_header;
163         }
164         copy_string(s, ch, file->disk, sizeof(file->disk), bp);
165         if(bp == NULL) {
166             goto weird_header;
167         }
168
169         skip_whitespace(s, ch);
170         if(ch == '\0') {
171             goto weird_header;
172         }
173         verify = s - 1;
174         skip_non_whitespace(s, ch);
175         s[-1] = '\0';
176         if(strcmp(verify, "lev") != 0) {
177             goto weird_header;
178         }
179
180         skip_whitespace(s, ch);
181         if(ch == '\0' || sscanf(s - 1, "%d", &file->dumplevel) != 1) {
182             goto weird_header;
183         }
184         skip_integer(s, ch);
185
186         skip_whitespace(s, ch);
187         if(ch == '\0') {
188             goto weird_header;
189         }
190         verify = s - 1;
191         skip_non_whitespace(s, ch);
192         s[-1] = '\0';
193         if(strcmp(verify, "comp") != 0) {
194             goto weird_header;
195         }
196
197         skip_whitespace(s, ch);
198         if(ch == '\0') {
199             goto weird_header;
200         }
201         copy_string(s, ch, file->comp_suffix, sizeof(file->comp_suffix), bp);
202         if(bp == NULL) {
203             goto weird_header;
204         }
205
206         file->compressed = strcmp(file->comp_suffix, "N");
207         /* compatibility with pre-2.2 amanda */
208         if(strcmp(file->comp_suffix, "C") == 0) {
209             strncpy(file->comp_suffix, ".Z", sizeof(file->comp_suffix)-1);
210             file->comp_suffix[sizeof(file->comp_suffix)-1] = '\0';
211         }
212
213         skip_whitespace(s, ch);
214         if(ch == '\0') {
215             return;                             /* "program" is optional */
216         }
217         verify = s - 1;
218         skip_non_whitespace(s, ch);
219         s[-1] = '\0';
220         if(strcmp(verify, "program") != 0) {
221             return;                             /* "program" is optional */
222         }
223
224         skip_whitespace(s, ch);
225         if(ch == '\0') {
226             goto weird_header;
227         }
228         copy_string(s, ch, file->program, sizeof(file->program), bp);
229         if(bp == NULL) {
230             goto weird_header;
231         }
232
233         if(file->program[0]=='\0') {
234             strncpy(file->program, "RESTORE", sizeof(file->program)-1);
235             file->program[sizeof(file->program)-1] = '\0';
236         }
237
238     } else if(strcmp(str, "TAPEEND") == 0) {
239         file->type = F_TAPEEND;
240
241         skip_whitespace(s, ch);
242         if(ch == '\0') {
243             goto weird_header;
244         }
245         verify = s - 1;
246         skip_non_whitespace(s, ch);
247         s[-1] = '\0';
248         if(strcmp(verify, "DATE") != 0) {
249             return;                             /* "program" is optional */
250         }
251
252         skip_whitespace(s, ch);
253         if(ch == '\0') {
254             goto weird_header;
255         }
256         copy_string(s, ch, file->datestamp, sizeof(file->datestamp), bp);
257         if(bp == NULL) {
258             goto weird_header;
259         }
260     } else {
261         goto weird_header;
262     }
263
264     done=0;
265     do {
266         /* isolate the next line */
267         int max_char;
268         ptr_buf++;
269         start_buf = ptr_buf;
270         max_char = buflen - (ptr_buf - buffer);
271         nchars = max_char<sizeof(line)? max_char : sizeof(line) - 1;
272         for(s=line ; ptr_buf < start_buf+nchars; ptr_buf++, s++) {
273             ch = *ptr_buf;
274             if(ch == '\n') {
275                 *s = '\0';
276                 break;
277             }
278             else if(ch == '\0' || ch == '\014') {
279                 done=1;
280                 break;
281             }
282             *s = ch;
283         }
284         if (done == 1) break;
285         if(ptr_buf >= start_buf+nchars) done = 1;
286         line[sizeof(line)-1] = '\0';
287         s = line;
288         ch = *s++;
289 #define SC "CONT_FILENAME="
290         if(strncmp(line,SC,strlen(SC)) == 0) {
291             s = line + strlen(SC);
292             ch = *s++;
293             copy_string(s, ch, file->cont_filename, 
294                         sizeof(file->cont_filename), bp);
295         }
296 #undef SC
297 #define SC "PARTIAL="
298         else if(strncmp(line,SC,strlen(SC)) == 0) {
299             s = line + strlen(SC);
300             if(strncmp(s,"yes",3)==0 || strncmp(s,"YES",3)==0)
301                 file->is_partial=1;
302             ch = *s++;
303         }
304 #undef SC
305 #define SC "To restore, position tape at start of file and run:"
306         else if(strncmp(line,SC,strlen(SC)) == 0) {
307         }
308 #undef SC
309 #define SC "\tdd if=<tape> bs="
310         else if(strncmp(line,SC,strlen(SC)) == 0) {
311             s = strtok(line, "|");
312             s1 = strtok(NULL, "|");
313             s2 = strtok(NULL, "|");
314             if(!s1) {
315                 strncpy(file->recover_cmd,"BUG",sizeof(file->recover_cmd));
316                 file->recover_cmd[sizeof(file->recover_cmd)-1] = '\0';
317             }
318             else if(!s2) {
319                 strncpy(file->recover_cmd,s1+1,sizeof(file->recover_cmd));
320                 file->recover_cmd[sizeof(file->recover_cmd)-1] = '\0';
321             }
322             else {
323                 strncpy(file->uncompress_cmd,s1, sizeof(file->uncompress_cmd));
324                 file->uncompress_cmd[sizeof(file->uncompress_cmd)-2] = '\0';
325                 strcat(file->uncompress_cmd,"|");
326                 strncpy(file->recover_cmd,s2+1,sizeof(file->recover_cmd));
327                 file->recover_cmd[sizeof(file->recover_cmd)-1] = '\0';
328             }
329         }
330 #undef SC
331         else { /* ignore unknown line */
332         }
333     } while(!done);
334
335     return;
336
337  weird_header:
338
339     fprintf(stderr, "%s: strange amanda header: \"%s\"\n", get_pname(), save_line);
340     file->type = F_WEIRD;
341     return;
342 }
343
344
345 void
346 build_header(buffer, file, buflen)
347     char *buffer;
348     dumpfile_t *file;
349     size_t buflen;
350 {
351     char *line = NULL;
352     char number[NUM_STR_SIZE*2];
353
354     memset(buffer,'\0',buflen);
355
356     switch (file->type) {
357     case F_TAPESTART: ap_snprintf(buffer, buflen,
358                                   "AMANDA: TAPESTART DATE %s TAPE %s\n\014\n",
359                                   file->datestamp, file->name);
360                       break;
361     case F_CONT_DUMPFILE:
362     case F_DUMPFILE : if( file->type == F_DUMPFILE) {
363                         ap_snprintf(buffer, buflen,
364                                   "AMANDA: FILE %s %s %s lev %d comp %s program %s\n",
365                                   file->datestamp, file->name, file->disk,
366                                   file->dumplevel, file->comp_suffix,
367                                   file->program);
368                       }
369                       else if( file->type == F_CONT_DUMPFILE) {
370                         ap_snprintf(buffer, buflen,
371                                   "AMANDA: CONT_FILE %s %s %s lev %d comp %s program %s\n",
372                                   file->datestamp, file->name, file->disk,
373                                   file->dumplevel, file->comp_suffix,
374                                   file->program);
375                       }
376                       buffer[buflen-1] = '\0';
377                       if(strlen(file->cont_filename) != 0) {
378                         line = newvstralloc(line, "CONT_FILENAME=",
379                                             file->cont_filename, "\n", NULL);
380                         strncat(buffer,line,buflen-strlen(buffer));
381                       }
382                       if(file->is_partial != 0) {
383                         strncat(buffer,"PARTIAL=YES\n",buflen-strlen(buffer));
384                       }
385                       strncat(buffer,
386                         "To restore, position tape at start of file and run:\n",
387                         buflen-strlen(buffer));
388                       ap_snprintf(number, sizeof(number),
389                                   "%ld", file->blocksize / 1024);
390                       line = newvstralloc(line, "\t",
391                                        "dd",
392                                        " if=<tape>",
393                                        " bs=", number, "k",
394                                        " skip=1",
395                                        " |", file->uncompress_cmd,
396                                        " ", file->recover_cmd,
397                                        "\n",
398                                        "\014\n",        /* ?? */
399                                        NULL);
400                       strncat(buffer, line, buflen-strlen(buffer));
401                       amfree(line);
402                       buffer[buflen-1] = '\0';
403                       break;
404     case F_TAPEEND  : ap_snprintf(buffer, buflen,
405                                   "AMANDA: TAPEEND DATE %s\n\014\n",
406                                   file->datestamp);
407                       break;
408     case F_UNKNOWN  : break;
409     case F_WEIRD    : break;
410     }
411 }
412
413
414 void print_header(outf, file)
415 FILE *outf;
416 dumpfile_t *file;
417 /*
418  * Prints the contents of the file structure.
419  */
420 {
421     switch(file->type) {
422     case F_UNKNOWN:
423         fprintf(outf, "UNKNOWN file\n");
424         break;
425     case F_WEIRD:
426         fprintf(outf, "WEIRD file\n");
427         break;
428     case F_TAPESTART:
429         fprintf(outf, "start of tape: date %s label %s\n",
430                file->datestamp, file->name);
431         break;
432     case F_DUMPFILE:
433         fprintf(outf, "dumpfile: date %s host %s disk %s lev %d comp %s",
434                 file->datestamp, file->name, file->disk, file->dumplevel, 
435                 file->comp_suffix);
436         if(*file->program)
437             fprintf(outf, " program %s\n",file->program);
438         else
439             fprintf(outf, "\n");
440         break;
441     case F_CONT_DUMPFILE:
442         fprintf(outf, "cont dumpfile: date %s host %s disk %s lev %d comp %s",
443                 file->datestamp, file->name, file->disk, file->dumplevel, 
444                 file->comp_suffix);
445         if(*file->program)
446             fprintf(outf, " program %s\n",file->program);
447         else
448             fprintf(outf, "\n");
449         break;
450     case F_TAPEEND:
451         fprintf(outf, "end of tape: date %s\n", file->datestamp);
452         break;
453     }
454 }
455
456
457 int known_compress_type(file)
458 dumpfile_t *file;
459 {
460     if(strcmp(file->comp_suffix, ".Z") == 0)
461         return 1;
462 #ifdef HAVE_GZIP
463     if(strcmp(file->comp_suffix, ".gz") == 0)
464         return 1;
465 #endif
466     return 0;
467 }