2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
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.
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.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: fileheader.c,v 1.34 2006/03/09 16:51:41 martinea Exp $
31 #include "fileheader.h"
33 static const char *filetype2str P((filetype_t));
34 static filetype_t str2filetype P((const char *));
40 memset(file, '\0', sizeof(*file));
41 file->blocksize = DISK_BLOCK_BYTES;
45 parse_file_header(buffer, file, buflen)
50 char *buf, *line, *tok, *line1=NULL;
52 /* put the buffer into a writable chunk of memory and nul-term it */
53 buf = alloc(buflen + 1);
54 memcpy(buf, buffer, buflen);
59 for(line=buf,lsize=0; *line != '\n' && lsize < buflen; line++) {lsize++;};
61 line1 = alloc(lsize+1);
62 strncpy(line1,buf,lsize);
66 tok = strtok(line1, " ");
69 if (strcmp(tok, "NETDUMP:") != 0 && strcmp(tok, "AMANDA:") != 0) {
71 file->type = F_UNKNOWN;
76 tok = strtok(NULL, " ");
79 file->type = str2filetype(tok);
83 tok = strtok(NULL, " ");
84 if (tok == NULL || strcmp(tok, "DATE") != 0)
87 tok = strtok(NULL, " ");
90 strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
92 tok = strtok(NULL, " ");
93 if (tok == NULL || strcmp(tok, "TAPE") != 0)
96 tok = strtok(NULL, " ");
99 strncpy(file->name, tok, sizeof(file->name) - 1);
103 case F_CONT_DUMPFILE:
104 case F_SPLIT_DUMPFILE:
105 tok = strtok(NULL, " ");
108 strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
110 tok = strtok(NULL, " ");
113 strncpy(file->name, tok, sizeof(file->name) - 1);
115 tok = strtok(NULL, " ");
118 strncpy(file->disk, tok, sizeof(file->disk) - 1);
120 if(file->type == F_SPLIT_DUMPFILE){
121 tok = strtok(NULL, " ");
122 if (tok == NULL || strcmp(tok, "part") != 0)
125 tok = strtok(NULL, "/");
126 if (tok == NULL || sscanf(tok, "%d", &file->partnum) != 1)
129 tok = strtok(NULL, " ");
132 /* If totalparts == -1, then the original dump was done in
133 streaming mode (no holding disk), thus we don't know how
134 many parts there are. */
135 if(sscanf(tok, "%d", &file->totalparts) != 1){
141 tok = strtok(NULL, " ");
142 if (tok == NULL || strcmp(tok, "lev") != 0)
145 tok = strtok(NULL, " ");
146 if (tok == NULL || sscanf(tok, "%d", &file->dumplevel) != 1)
149 tok = strtok(NULL, " ");
150 if (tok == NULL || strcmp(tok, "comp") != 0)
153 tok = strtok(NULL, " ");
156 strncpy(file->comp_suffix, tok, sizeof(file->comp_suffix) - 1);
158 file->compressed = strcmp(file->comp_suffix, "N");
159 /* compatibility with pre-2.2 amanda */
160 if (strcmp(file->comp_suffix, "C") == 0)
161 strncpy(file->comp_suffix, ".Z", sizeof(file->comp_suffix) - 1);
163 tok = strtok(NULL, " ");
164 /* "program" is optional */
165 if (tok == NULL || strcmp(tok, "program") != 0) {
171 tok = strtok(NULL, " ");
174 strncpy(file->program, tok, sizeof(file->program) - 1);
175 if (file->program[0] == '\0')
176 strncpy(file->program, "RESTORE", sizeof(file->program) - 1);
178 if ((tok = strtok(NULL, " ")) == NULL)
179 break; /* reach the end of the buf */
181 /* "encryption" is optional */
182 if (BSTRNCMP(tok, "crypt") == 0) {
183 tok = strtok(NULL, " ");
186 strncpy(file->encrypt_suffix, tok,
187 sizeof(file->encrypt_suffix) - 1);
188 file->encrypted = BSTRNCMP(file->encrypt_suffix, "N");
189 if ((tok = strtok(NULL, " ")) == NULL)
193 /* "srvcompprog" is optional */
194 if (BSTRNCMP(tok, "server_custom_compress") == 0) {
195 tok = strtok(NULL, " ");
198 strncpy(file->srvcompprog, tok, sizeof(file->srvcompprog) - 1);
199 if ((tok = strtok(NULL, " ")) == NULL)
203 /* "clntcompprog" is optional */
204 if (BSTRNCMP(tok, "client_custom_compress") == 0) {
205 tok = strtok(NULL, " ");
208 strncpy(file->clntcompprog, tok, sizeof(file->clntcompprog) - 1);
209 if ((tok = strtok(NULL, " ")) == NULL)
213 /* "srv_encrypt" is optional */
214 if (BSTRNCMP(tok, "server_encrypt") == 0) {
215 tok = strtok(NULL, " ");
218 strncpy(file->srv_encrypt, tok, sizeof(file->srv_encrypt) - 1);
219 if ((tok = strtok(NULL, " ")) == NULL)
223 /* "clnt_encrypt" is optional */
224 if (BSTRNCMP(tok, "client_encrypt") == 0) {
225 tok = strtok(NULL, " ");
228 strncpy(file->clnt_encrypt, tok, sizeof(file->clnt_encrypt) - 1);
229 if ((tok = strtok(NULL, " ")) == NULL)
233 /* "srv_decrypt_opt" is optional */
234 if (BSTRNCMP(tok, "server_decrypt_option") == 0) {
235 tok = strtok(NULL, " ");
238 strncpy(file->srv_decrypt_opt, tok,
239 sizeof(file->srv_decrypt_opt) - 1);
240 if ((tok = strtok(NULL, " ")) == NULL)
244 /* "clnt_decrypt_opt" is optional */
245 if (BSTRNCMP(tok, "client_decrypt_option") == 0) {
246 tok = strtok(NULL, " ");
249 strncpy(file->clnt_decrypt_opt, tok,
250 sizeof(file->clnt_decrypt_opt) - 1);
251 if ((tok = strtok(NULL, " ")) == NULL)
258 tok = strtok(NULL, " ");
259 /* DATE is optional */
260 if (tok == NULL || strcmp(tok, "DATE") != 0) {
265 strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
272 line = strtok(buf, "\n"); /* this is the first line */
273 /* iterate through the rest of the lines */
274 while ((line = strtok(NULL, "\n")) != NULL) {
275 #define SC "CONT_FILENAME="
276 if (strncmp(line, SC, sizeof(SC) - 1) == 0) {
277 line += sizeof(SC) - 1;
278 strncpy(file->cont_filename, line,
279 sizeof(file->cont_filename) - 1);
284 #define SC "PARTIAL="
285 if (strncmp(line, SC, sizeof(SC) - 1) == 0) {
286 line += sizeof(SC) - 1;
287 file->is_partial = !strcasecmp(line, "yes");
292 #define SC "To restore, position tape at start of file and run:"
293 if (strncmp(line, SC, sizeof(SC) - 1) == 0)
297 #define SC "\tdd if=<tape> bs="
298 if (strncmp(line, SC, sizeof(SC) - 1) == 0) {
299 char *cmd1=NULL, *cmd2=NULL, *cmd3=NULL;
301 /* skip over dd command */
302 if ((cmd1 = strchr(line, '|')) == NULL) {
304 strncpy(file->recover_cmd, "BUG",
305 sizeof(file->recover_cmd) - 1);
310 /* block out first pipeline command */
311 if ((cmd2 = strchr(cmd1, '|')) != NULL) {
313 if ((cmd3 = strchr(cmd2, '|')) != NULL)
317 /* three cmds: decrypt | uncompress | recover
318 * two cmds: uncompress | recover
319 * XXX note that if there are two cmds, the first one
320 * XXX could be either uncompress or decrypt. Since no
321 * XXX code actually call uncompress_cmd/decrypt_cmd, it's ok
322 * XXX for header information.
328 strncpy(file->recover_cmd, cmd1,
329 sizeof(file->recover_cmd) - 1);
331 snprintf(file->uncompress_cmd,
332 sizeof(file->uncompress_cmd), "%s|", cmd1);
333 strncpy(file->recover_cmd, cmd2,
334 sizeof(file->recover_cmd) - 1);
336 } else { /* cmd3 presents: decrypt | uncompress | recover */
337 snprintf(file->decrypt_cmd,
338 sizeof(file->decrypt_cmd), "%s|", cmd1);
339 snprintf(file->uncompress_cmd,
340 sizeof(file->uncompress_cmd), "%s|", cmd2);
341 strncpy(file->recover_cmd, cmd3,
342 sizeof(file->recover_cmd) - 1);
347 /* XXX complain about weird lines? */
354 fprintf(stderr, "%s: strange amanda header: \"%.*s\"\n", get_pname(),
355 (int) buflen, buffer);
356 file->type = F_WEIRD;
362 build_header(buffer, file, buflen)
364 const dumpfile_t *file;
368 char split_data[128] = "";
370 memset(buffer,'\0',buflen);
372 switch (file->type) {
374 snprintf(buffer, buflen,
375 "AMANDA: TAPESTART DATE %s TAPE %s\n014\n",
376 file->datestamp, file->name);
379 case F_SPLIT_DUMPFILE:
380 snprintf(split_data, sizeof(split_data),
381 " part %d/%d ", file->partnum, file->totalparts);
384 case F_CONT_DUMPFILE:
386 n = snprintf(buffer, buflen,
387 "AMANDA: %s %s %s %s %s lev %d comp %s program %s",
388 filetype2str(file->type),
389 file->datestamp, file->name, file->disk,
391 file->dumplevel, file->comp_suffix, file->program);
398 if (strcmp(file->encrypt_suffix, "enc") == 0) { /* only output crypt if it's enabled */
399 n = snprintf(buffer, buflen, " crypt %s", file->encrypt_suffix);
407 if (*file->srvcompprog) {
408 n = snprintf(buffer, buflen, " server_custom_compress %s", file->srvcompprog);
409 } else if (*file->clntcompprog) {
410 n = snprintf(buffer, buflen, " client_custom_compress %s", file->clntcompprog);
419 if (*file->srv_encrypt) {
420 n = snprintf(buffer, buflen, " server_encrypt %s", file->srv_encrypt);
421 } else if (*file->clnt_encrypt) {
422 n = snprintf(buffer, buflen, " client_encrypt %s", file->clnt_encrypt);
431 if (*file->srv_decrypt_opt) {
432 n = snprintf(buffer, buflen, " server_decrypt_option %s", file->srv_decrypt_opt);
433 } else if (*file->clnt_decrypt_opt) {
434 n = snprintf(buffer, buflen, " client_decrypt_option %s", file->clnt_decrypt_opt);
443 n = snprintf(buffer, buflen, "\n");
447 if (file->cont_filename[0] != '\0') {
448 n = snprintf(buffer, buflen, "CONT_FILENAME=%s\n",
449 file->cont_filename);
453 if (file->is_partial != 0) {
454 n = snprintf(buffer, buflen, "PARTIAL=YES\n");
459 n = snprintf(buffer, buflen,
460 "To restore, position tape at start of file and run:\n");
465 n = snprintf(buffer, buflen,
466 "\tdd if=<tape> bs=%ldk skip=1 |%s %s %s\n\014\n",
467 file->blocksize / 1024, file->decrypt_cmd, file->uncompress_cmd, file->recover_cmd);
473 snprintf(buffer, buflen, "AMANDA: TAPEEND DATE %s\n\014\n",
484 * Prints the contents of the file structure.
487 print_header(outf, file)
489 const dumpfile_t *file;
491 char number[NUM_STR_SIZE*2];
494 fprintf(outf, "UNKNOWN file\n");
497 fprintf(outf, "WEIRD file\n");
500 fprintf(outf, "start of tape: date %s label %s\n",
501 file->datestamp, file->name);
504 case F_CONT_DUMPFILE:
505 fprintf(outf, "%s: date %s host %s disk %s lev %d comp %s",
506 filetype2str(file->type), file->datestamp, file->name,
507 file->disk, file->dumplevel, file->comp_suffix);
509 fprintf(outf, " program %s",file->program);
510 if (strcmp(file->encrypt_suffix, "enc") == 0)
511 fprintf(outf, " crypt %s", file->encrypt_suffix);
512 if (*file->srvcompprog)
513 fprintf(outf, " server_custom_compress %s", file->srvcompprog);
514 if (*file->clntcompprog)
515 fprintf(outf, " client_custom_compress %s", file->clntcompprog);
516 if (*file->srv_encrypt)
517 fprintf(outf, " server_encrypt %s", file->srv_encrypt);
518 if (*file->clnt_encrypt)
519 fprintf(outf, " client_encrypt %s", file->clnt_encrypt);
520 if (*file->srv_decrypt_opt)
521 fprintf(outf, " server_decrypt_option %s", file->srv_decrypt_opt);
522 if (*file->clnt_decrypt_opt)
523 fprintf(outf, " client_decrypt_option %s", file->clnt_decrypt_opt);
526 case F_SPLIT_DUMPFILE:
527 if(file->totalparts > 0){
528 snprintf(number, sizeof(number), "%d", file->totalparts);
530 else snprintf(number, sizeof(number), "UNKNOWN");
531 fprintf(outf, "split dumpfile: date %s host %s disk %s part %d/%s lev %d comp %s",
532 file->datestamp, file->name, file->disk, file->partnum,
533 number, file->dumplevel, file->comp_suffix);
535 fprintf(outf, " program %s",file->program);
536 if (strcmp(file->encrypt_suffix, "enc") == 0)
537 fprintf(outf, " crypt %s", file->encrypt_suffix);
538 if (*file->srvcompprog)
539 fprintf(outf, " server_custom_compress %s", file->srvcompprog);
540 if (*file->clntcompprog)
541 fprintf(outf, " client_custom_compress %s", file->clntcompprog);
542 if (*file->srv_encrypt)
543 fprintf(outf, " server_encrypt %s", file->srv_encrypt);
544 if (*file->clnt_encrypt)
545 fprintf(outf, " client_encrypt %s", file->clnt_encrypt);
546 if (*file->srv_decrypt_opt)
547 fprintf(outf, " server_decrypt_option %s", file->srv_decrypt_opt);
548 if (*file->clnt_decrypt_opt)
549 fprintf(outf, " client_decrypt_option %s", file->clnt_decrypt_opt);
553 fprintf(outf, "end of tape: date %s\n", file->datestamp);
559 known_compress_type(file)
560 const dumpfile_t *file;
562 if(strcmp(file->comp_suffix, ".Z") == 0)
565 if(strcmp(file->comp_suffix, ".gz") == 0)
568 if(strcmp(file->comp_suffix, "cust") == 0)
573 static const struct {
577 { F_UNKNOWN, "UNKNOWN" },
578 { F_WEIRD, "WEIRD" },
579 { F_TAPESTART, "TAPESTART" },
580 { F_TAPEEND, "TAPEEND" },
581 { F_DUMPFILE, "FILE" },
582 { F_CONT_DUMPFILE, "CONT_FILE" },
583 { F_SPLIT_DUMPFILE, "SPLIT_FILE" }
585 #define NFILETYPES (sizeof(filetypetab) / sizeof(filetypetab[0]))
593 for (i = 0; i < NFILETYPES; i++)
594 if (filetypetab[i].type == type)
595 return (filetypetab[i].str);
605 for (i = 0; i < NFILETYPES; i++)
606 if (strcmp(filetypetab[i].str, str) == 0)
607 return (filetypetab[i].type);