* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: fileheader.c,v 1.40 2006/07/01 00:10:38 paddy_s Exp $
+ * $Id: fileheader.c 6512 2007-05-24 17:00:24Z ian $
*/
#include "amanda.h"
#include "fileheader.h"
+#include "match.h"
+#include <glib.h>
+#include "util.h"
static const char * filetype2str(filetype_t);
static filetype_t str2filetype(const char *);
static void strange_header(dumpfile_t *, const char *,
size_t, const char *, const char *);
+static char *quote_heredoc(char *text, char *delimiter_prefix);
+static char *parse_heredoc(char *line, char **saveptr);
void
fh_init(
dumpfile_t *file)
{
memset(file, '\0', SIZEOF(*file));
- file->blocksize = DISK_BLOCK_BYTES;
+ file->type = F_EMPTY;
+ file->blocksize = 0;
}
static void
if (expected == NULL)
expected = "<null>";
- fprintf(stderr, "%s: strange amanda header: \"%.*s\"\n", get_pname(),
- (int)buflen, buffer);
-
- fprintf(stderr, "%s: Expected: \"%s\" Actual: \"%s\"\n", get_pname(),
- expected, actual);
+ g_debug("strange amanda header: \"%.*s\"", (int)buflen, buffer);
+ g_debug("Expected: \"%s\" Actual: \"%s\"", expected, actual);
file->type = F_WEIRD;
}
+/* chop whitespace off of a string, in place */
+static void
+chomp(char *str)
+{
+ char *s = str;
+
+ if (!str)
+ return;
+
+ /* trim leading space */
+ while (g_ascii_isspace(*s)) { s++; }
+ if (s != str)
+ memmove(str, s, strlen(s)+1);
+
+ /* trim trailing space */
+ if (*str) {
+ for (s = str+strlen(str)-1; s >= str; s--) {
+ if (!g_ascii_isspace(*s))
+ break;
+ *s = '\0';
+ }
+ }
+}
void
parse_file_header(
size_t lsize;
char *uqname;
int in_quotes;
+ char *saveptr = NULL;
/* put the buffer into a writable chunk of memory and nul-term it */
buf = alloc(buflen + 1);
buf[buflen] = '\0';
fh_init(file);
+ /* extract the first unquoted line */
in_quotes = 0;
for (line = buf, lsize = 0; lsize < buflen; line++) {
if ((*line == '\n') && !in_quotes)
line1[lsize] = '\0';
*line = '\n';
- tok = strtok(line1, " ");
+ tok = strtok_r(line1, " ", &saveptr);
if (tok == NULL) {
- fprintf(stderr, "%s: Empty amanda header: buflen=" SIZE_T_FMT
- " lsize=" SIZE_T_FMT "\n", get_pname(),
- (SIZE_T_FMT_TYPE)buflen,
- (SIZE_T_FMT_TYPE)lsize);
- hexdump(buffer, lsize);
- strange_header(file, buffer, buflen, "<Non-empty line>", tok);
+ g_debug("Empty amanda header: buflen=%zu lsize=%zu", buflen, lsize);
+ strange_header(file, buffer, buflen, _("<Non-empty line>"), tok);
goto out;
}
return;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<file type>", tok);
+ strange_header(file, buffer, buflen, _("<file type>"), tok);
goto out;
}
file->type = str2filetype(tok);
switch (file->type) {
case F_TAPESTART:
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if ((tok == NULL) || (strcmp(tok, "DATE") != 0)) {
strange_header(file, buffer, buflen, "DATE", tok);
goto out;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<date stamp>", tok);
+ strange_header(file, buffer, buflen, _("<date stamp>"), tok);
goto out;
}
strncpy(file->datestamp, tok, SIZEOF(file->datestamp) - 1);
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if ((tok == NULL) || (strcmp(tok, "TAPE") != 0)) {
strange_header(file, buffer, buflen, "TAPE", tok);
goto out;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<file type>", tok);
+ strange_header(file, buffer, buflen, _("<file type>"), tok);
goto out;
}
strncpy(file->name, tok, SIZEOF(file->name) - 1);
case F_DUMPFILE:
case F_CONT_DUMPFILE:
case F_SPLIT_DUMPFILE:
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<date stamp>", tok);
+ strange_header(file, buffer, buflen, _("<date stamp>"), tok);
goto out;
}
strncpy(file->datestamp, tok, SIZEOF(file->datestamp) - 1);
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<file name>", tok);
+ strange_header(file, buffer, buflen, _("<file name>"), tok);
goto out;
}
strncpy(file->name, tok, SIZEOF(file->name) - 1);
- tok = strquotedstr();
+ tok = strquotedstr(&saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<disk name>", tok);
+ strange_header(file, buffer, buflen, _("<disk name>"), tok);
goto out;
}
uqname = unquote_string(tok);
amfree(uqname);
if(file->type == F_SPLIT_DUMPFILE) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL || strcmp(tok, "part") != 0) {
strange_header(file, buffer, buflen, "part", tok);
goto out;
}
- tok = strtok(NULL, "/");
+ tok = strtok_r(NULL, "/", &saveptr);
if ((tok == NULL) || (sscanf(tok, "%d", &file->partnum) != 1)) {
- strange_header(file, buffer, buflen, "<part num param>", tok);
+ strange_header(file, buffer, buflen, _("<part num param>"), tok);
goto out;
}
/* If totalparts == -1, then the original dump was done in
streaming mode (no holding disk), thus we don't know how
many parts there are. */
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if((tok == NULL) || (sscanf(tok, "%d", &file->totalparts) != 1)) {
- strange_header(file, buffer, buflen, "<total parts param>", tok);
+ strange_header(file, buffer, buflen, _("<total parts param>"), tok);
goto out;
}
+ } else if (file->type == F_DUMPFILE) {
+ /* only one part in this dump, so call it partnum 1 */
+ file->partnum = 1;
+ file->totalparts = 1;
+ } else {
+ file->partnum = 0;
+ file->totalparts = 0;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if ((tok == NULL) || (strcmp(tok, "lev") != 0)) {
strange_header(file, buffer, buflen, "lev", tok);
goto out;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if ((tok == NULL) || (sscanf(tok, "%d", &file->dumplevel) != 1)) {
- strange_header(file, buffer, buflen, "<dump level param>", tok);
+ strange_header(file, buffer, buflen, _("<dump level param>"), tok);
goto out;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if ((tok == NULL) || (strcmp(tok, "comp") != 0)) {
strange_header(file, buffer, buflen, "comp", tok);
goto out;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<comp param>", tok);
+ strange_header(file, buffer, buflen, _("<comp param>"), tok);
goto out;
}
strncpy(file->comp_suffix, tok, SIZEOF(file->comp_suffix) - 1);
- file->compressed = strcmp(file->comp_suffix, "N");
- /* compatibility with pre-2.2 amanda */
- if (strcmp(file->comp_suffix, "C") == 0)
- strncpy(file->comp_suffix, ".Z", SIZEOF(file->comp_suffix) - 1);
-
- tok = strtok(NULL, " ");
+ file->compressed = (0 != strcmp(file->comp_suffix, "N"));
+ if (file->compressed) {
+ /* compatibility with pre-2.2 amanda */
+ if (strcmp(file->comp_suffix, "C") == 0)
+ strncpy(file->comp_suffix, ".Z", SIZEOF(file->comp_suffix) - 1);
+ } else {
+ strcpy(file->comp_suffix, "");
+ }
+
+ tok = strtok_r(NULL, " ", &saveptr);
/* "program" is optional */
if (tok == NULL || strcmp(tok, "program") != 0) {
- amfree(buf);
- amfree(line1);
- return;
+ break;
}
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<program name>", tok);
+ strange_header(file, buffer, buflen, _("<program name>"), tok);
goto out;
}
strncpy(file->program, tok, SIZEOF(file->program) - 1);
- if (file->program[0] == '\0')
- strncpy(file->program, "RESTORE", SIZEOF(file->program) - 1);
- if ((tok = strtok(NULL, " ")) == NULL)
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break; /* reached the end of the buffer */
- /* "encryption" is optional */
+ /* encryption is optional */
if (BSTRNCMP(tok, "crypt") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
- strange_header(file, buffer, buflen, "<crypt param>", tok);
+ strange_header(file, buffer, buflen, _("<crypt param>"), tok);
goto out;
}
strncpy(file->encrypt_suffix, tok,
SIZEOF(file->encrypt_suffix) - 1);
- file->encrypted = BSTRNCMP(file->encrypt_suffix, "N");
- if ((tok = strtok(NULL, " ")) == NULL)
+ file->encrypted = 1;
+
+ /* for compatibility with who-knows-what, allow "comp N" to be
+ * equivalent to no compression */
+ if (0 == BSTRNCMP(file->encrypt_suffix, "N")) {
+ file->encrypted = 0;
+ strcpy(file->encrypt_suffix, "");
+ }
+
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break;
}
/* "srvcompprog" is optional */
if (BSTRNCMP(tok, "server_custom_compress") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
strange_header(file, buffer, buflen,
- "<server custom compress param>", tok);
+ _("<server custom compress param>"), tok);
goto out;
}
strncpy(file->srvcompprog, tok, SIZEOF(file->srvcompprog) - 1);
- if ((tok = strtok(NULL, " ")) == NULL)
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break;
}
/* "clntcompprog" is optional */
if (BSTRNCMP(tok, "client_custom_compress") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
strange_header(file, buffer, buflen,
- "<client custom compress param>", tok);
+ _("<client custom compress param>"), tok);
goto out;
}
strncpy(file->clntcompprog, tok, SIZEOF(file->clntcompprog) - 1);
- if ((tok = strtok(NULL, " ")) == NULL)
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break;
}
/* "srv_encrypt" is optional */
if (BSTRNCMP(tok, "server_encrypt") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
strange_header(file, buffer, buflen,
- "<server encrypt param>", tok);
+ _("<server encrypt param>"), tok);
goto out;
}
strncpy(file->srv_encrypt, tok, SIZEOF(file->srv_encrypt) - 1);
- if ((tok = strtok(NULL, " ")) == NULL)
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break;
}
/* "clnt_encrypt" is optional */
if (BSTRNCMP(tok, "client_encrypt") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
strange_header(file, buffer, buflen,
- "<client encrypt param>", tok);
+ _("<client encrypt param>"), tok);
goto out;
}
strncpy(file->clnt_encrypt, tok, SIZEOF(file->clnt_encrypt) - 1);
- if ((tok = strtok(NULL, " ")) == NULL)
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break;
}
/* "srv_decrypt_opt" is optional */
if (BSTRNCMP(tok, "server_decrypt_option") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
strange_header(file, buffer, buflen,
- "<server decrypt param>", tok);
+ _("<server decrypt param>"), tok);
goto out;
}
strncpy(file->srv_decrypt_opt, tok,
SIZEOF(file->srv_decrypt_opt) - 1);
- if ((tok = strtok(NULL, " ")) == NULL)
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break;
}
/* "clnt_decrypt_opt" is optional */
if (BSTRNCMP(tok, "client_decrypt_option") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if (tok == NULL) {
strange_header(file, buffer, buflen,
- "<client decrypt param>", tok);
+ _("<client decrypt param>"), tok);
goto out;
}
strncpy(file->clnt_decrypt_opt, tok,
SIZEOF(file->clnt_decrypt_opt) - 1);
- if ((tok = strtok(NULL, " ")) == NULL)
+ if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
break;
}
break;
case F_TAPEEND:
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
/* DATE is optional */
if (tok != NULL) {
if (strcmp(tok, "DATE") == 0) {
- tok = strtok(NULL, " ");
+ tok = strtok_r(NULL, " ", &saveptr);
if(tok == NULL)
file->datestamp[0] = '\0';
else
strncpy(file->datestamp, tok, SIZEOF(file->datestamp) - 1);
} else {
- strange_header(file, buffer, buflen, "<DATE>", tok);
+ strange_header(file, buffer, buflen, _("<DATE>"), tok);
}
} else {
file->datestamp[0] = '\0';
}
break;
+ case F_NOOP:
+ /* nothing follows */
+ break;
+
default:
strange_header(file, buffer, buflen,
- "TAPESTART|DUMPFILE|CONT_DUMPFILE|SPLIT_DUMPFILE|TAPEEND", tok);
+ _("TAPESTART|DUMPFILE|CONT_DUMPFILE|SPLIT_DUMPFILE|TAPEEND|NOOP"), tok);
goto out;
}
- (void)strtok(buf, "\n"); /* this is the first line */
+ (void)strtok_r(buf, "\n", &saveptr); /* this is the first line */
/* iterate through the rest of the lines */
- while ((line = strtok(NULL, "\n")) != NULL) {
+ while ((line = strtok_r(NULL, "\n", &saveptr)) != NULL) {
#define SC "CONT_FILENAME="
if (strncmp(line, SC, SIZEOF(SC) - 1) == 0) {
line += SIZEOF(SC) - 1;
strncpy(file->cont_filename, line,
SIZEOF(file->cont_filename) - 1);
- continue;
+ continue;
}
#undef SC
continue;
}
#undef SC
+#define SC "APPLICATION="
+ if (strncmp(line, SC, SIZEOF(SC) - 1) == 0) {
+ line += SIZEOF(SC) - 1;
+ strncpy(file->application, line,
+ SIZEOF(file->application) - 1);
+ continue;
+ }
+#undef SC
+
+#define SC "ORIGSIZE="
+ if (strncmp(line, SC, SIZEOF(SC) - 1) == 0) {
+ line += SIZEOF(SC) - 1;
+ file->orig_size = OFF_T_ATOI(line);
+ }
+#undef SC
+
+#define SC "DLE="
+ if (strncmp(line, SC, SIZEOF(SC) - 1) == 0) {
+ line += SIZEOF(SC) - 1;
+ file->dle_str = parse_heredoc(line, &saveptr);
+ }
+#undef SC
-#define SC "To restore, position tape at start of file and run:"
+#define SC _("To restore, position tape at start of file and run:")
if (strncmp(line, SC, SIZEOF(SC) - 1) == 0)
continue;
#undef SC
-#define SC "\tdd if=<tape> bs="
+#define SC "\tdd if=<tape> "
if (strncmp(line, SC, SIZEOF(SC) - 1) == 0) {
char *cmd1, *cmd2, *cmd3=NULL;
*cmd3++ = '\0';
}
+ /* clean up some extra spaces in various fields */
+ chomp(cmd1);
+ chomp(cmd2);
+ chomp(cmd3);
+
/* three cmds: decrypt | uncompress | recover
* two cmds: uncompress | recover
* XXX note that if there are two cmds, the first one
strncpy(file->recover_cmd, cmd1,
SIZEOF(file->recover_cmd) - 1);
} else {
- snprintf(file->uncompress_cmd,
- SIZEOF(file->uncompress_cmd), "%s|", cmd1);
+ g_snprintf(file->uncompress_cmd,
+ SIZEOF(file->uncompress_cmd), "%s |", cmd1);
strncpy(file->recover_cmd, cmd2,
SIZEOF(file->recover_cmd) - 1);
}
} else { /* cmd3 presents: decrypt | uncompress | recover */
- snprintf(file->decrypt_cmd,
- SIZEOF(file->decrypt_cmd), "%s|", cmd1);
- snprintf(file->uncompress_cmd,
- SIZEOF(file->uncompress_cmd), "%s|", cmd2);
+ g_snprintf(file->decrypt_cmd,
+ SIZEOF(file->decrypt_cmd), "%s |", cmd1);
+ g_snprintf(file->uncompress_cmd,
+ SIZEOF(file->uncompress_cmd), "%s |", cmd2);
strncpy(file->recover_cmd, cmd3,
SIZEOF(file->recover_cmd) - 1);
}
dump_dumpfile_t(
const dumpfile_t *file)
{
- const char *pname = get_pname();
-
- dbprintf(("%s: Contents of *(dumpfile_t *)%p:\n", pname, file));
- dbprintf(("%s: type = %d (%s)\n", pname,
- file->type, filetype2str(file->type)));
- dbprintf(("%s: datestamp = '%s'\n", pname,
- file->datestamp));
- dbprintf(("%s: dumplevel = %d\n", pname, file->dumplevel));
- dbprintf(("%s: compressed = %d\n", pname, file->compressed));
- dbprintf(("%s: encrypted = %d\n", pname, file->encrypted));
- dbprintf(("%s: comp_suffix = '%s'\n", pname,
- file->comp_suffix));
- dbprintf(("%s: encrypt_suffix = '%s'\n", pname,
- file->encrypt_suffix));
- dbprintf(("%s: name = '%s'\n", pname, file->name));
- dbprintf(("%s: disk = '%s'\n", pname, file->disk));
- dbprintf(("%s: program = '%s'\n", pname, file->program));
- dbprintf(("%s: srvcompprog = '%s'\n", pname,
- file->srvcompprog));
- dbprintf(("%s: clntcompprog = '%s'\n", pname,
- file->clntcompprog));
- dbprintf(("%s: srv_encrypt = '%s'\n", pname,
- file->srv_encrypt));
- dbprintf(("%s: clnt_encrypt = '%s'\n", pname,
- file->clnt_encrypt));
- dbprintf(("%s: recover_cmd = '%s'\n", pname,
- file->recover_cmd));
- dbprintf(("%s: uncompress_cmd = '%s'\n", pname,
- file->uncompress_cmd));
- dbprintf(("%s: encrypt_cmd = '%s'\n", pname,
- file->encrypt_cmd));
- dbprintf(("%s: decrypt_cmd = '%s'\n", pname,
- file->decrypt_cmd));
- dbprintf(("%s: srv_decrypt_opt = '%s'\n", pname,
- file->srv_decrypt_opt));
- dbprintf(("%s: clnt_decrypt_opt = '%s'\n", pname,
- file->clnt_decrypt_opt));
- dbprintf(("%s: cont_filename = '%s'\n", pname,
- file->cont_filename));
- dbprintf(("%s: is_partial = %d\n", pname, file->is_partial));
- dbprintf(("%s: partnum = %d\n", pname, file->partnum));
- dbprintf(("%s: totalparts = %d\n", pname, file->totalparts));
- dbprintf(("%s: blocksize = " SIZE_T_FMT "\n", pname,
- (SIZE_T_FMT_TYPE)file->blocksize));
+ g_debug(_("Contents of *(dumpfile_t *)%p:"), file);
+ g_debug(_(" type = %d (%s)"),
+ file->type, filetype2str(file->type));
+ g_debug(_(" datestamp = '%s'"), file->datestamp);
+ g_debug(_(" dumplevel = %d"), file->dumplevel);
+ g_debug(_(" compressed = %d"), file->compressed);
+ g_debug(_(" encrypted = %d"), file->encrypted);
+ g_debug(_(" comp_suffix = '%s'"), file->comp_suffix);
+ g_debug(_(" encrypt_suffix = '%s'"), file->encrypt_suffix);
+ g_debug(_(" name = '%s'"), file->name);
+ g_debug(_(" disk = '%s'"), file->disk);
+ g_debug(_(" program = '%s'"), file->program);
+ g_debug(_(" application = '%s'"), file->application);
+ g_debug(_(" srvcompprog = '%s'"), file->srvcompprog);
+ g_debug(_(" clntcompprog = '%s'"), file->clntcompprog);
+ g_debug(_(" srv_encrypt = '%s'"), file->srv_encrypt);
+ g_debug(_(" clnt_encrypt = '%s'"), file->clnt_encrypt);
+ g_debug(_(" recover_cmd = '%s'"), file->recover_cmd);
+ g_debug(_(" uncompress_cmd = '%s'"), file->uncompress_cmd);
+ g_debug(_(" decrypt_cmd = '%s'"), file->decrypt_cmd);
+ g_debug(_(" srv_decrypt_opt = '%s'"), file->srv_decrypt_opt);
+ g_debug(_(" clnt_decrypt_opt = '%s'"), file->clnt_decrypt_opt);
+ g_debug(_(" cont_filename = '%s'"), file->cont_filename);
+ if (file->dle_str)
+ g_debug(_(" dle_str = %s"), file->dle_str);
+ else
+ g_debug(_(" dle_str = (null)"));
+ g_debug(_(" is_partial = %d"), file->is_partial);
+ g_debug(_(" partnum = %d"), file->partnum);
+ g_debug(_(" totalparts = %d"), file->totalparts);
+ if (file->blocksize)
+ g_debug(_(" blocksize = %zu"), file->blocksize);
}
static void
-validate_name(
+validate_nonempty_str(
+ const char *val,
const char *name)
{
- if (strlen(name) == 0) {
- error("Invalid name '%s'\n", name);
- /*NOTREACHED*/
+ if (strlen(val) == 0) {
+ error(_("Invalid %s '%s'\n"), name, val);
+ /*NOTREACHED*/
+ }
+}
+
+static void
+validate_not_both(
+ const char *val1, const char *val2,
+ const char *name1, const char *name2)
+{
+ if (*val1 && *val2) {
+ error("cannot set both %s and %s\n", name1, name2);
+ }
+}
+
+static void
+validate_no_space(
+ const char *val,
+ const char *name)
+{
+ if (strchr(val, ' ') != NULL) {
+ error(_("%s cannot contain spaces\n"), name);
+ /*NOTREACHED*/
+ }
+}
+
+static void
+validate_pipe_cmd(
+ const char *cmd,
+ const char *name)
+{
+ if (strlen(cmd) && cmd[strlen(cmd)-1] != '|') {
+ error("invalid %s (must end with '|'): '%s'\n", name, cmd);
+ }
+}
+
+static void
+validate_encrypt_suffix(
+ int encrypted,
+ const char *suff)
+{
+ if (encrypted) {
+ if (!suff[0] || (0 == strcmp(suff, "N"))) {
+ error(_("Invalid encrypt_suffix '%s'\n"), suff);
+ }
+ } else {
+ if (suff[0] && (0 != strcmp(suff, "N"))) {
+ error(_("Invalid header: encrypt_suffix '%s' specified but not encrypted\n"), suff);
}
+ }
}
static void
if ((strlen(datestamp) == 14) && match("^[0-9]{14}$", datestamp)) {
return;
}
- error("Invalid datestamp '%s'\n", datestamp);
+ error(_("Invalid datestamp '%s'\n"), datestamp);
/*NOTREACHED*/
}
const int totalparts)
{
if (partnum < 1) {
- error("Invalid partnum (%d)\n", partnum);
+ error(_("Invalid partnum (%d)\n"), partnum);
/*NOTREACHED*/
}
if (partnum > totalparts && totalparts >= 0) {
- error("Invalid partnum (%d) > totalparts (%d)\n",
+ error(_("Invalid partnum (%d) > totalparts (%d)\n"),
partnum, totalparts);
/*NOTREACHED*/
}
}
-void
-build_header(
- char * buffer,
- const dumpfile_t * file,
- size_t buflen)
+char *
+build_header(const dumpfile_t * file, size_t *size, size_t max_size)
{
- int n;
+ GString *rval, *split_data;
char *qname;
- char split_data[128] = "";
+ char *program;
+ size_t min_size;
- dbprintf(("%s: Building type %d (%s) header of size " SIZE_T_FMT " using:\n",
- get_pname(), file->type, filetype2str(file->type),
- (SIZE_T_FMT_TYPE)buflen));
- dump_dumpfile_t(file);
+ min_size = size? *size : max_size;
+ g_debug(_("Building type %s header of %zu-%zu bytes with name='%s' disk='%s' dumplevel=%d and blocksize=%zu"),
+ filetype2str(file->type), min_size, max_size,
+ file->name, file->disk, file->dumplevel, file->blocksize);
- memset(buffer,'\0',buflen);
+ rval = g_string_sized_new(min_size);
+ split_data = g_string_sized_new(10);
switch (file->type) {
case F_TAPESTART:
- validate_name(file->name);
+ validate_nonempty_str(file->name, "name");
validate_datestamp(file->datestamp);
- snprintf(buffer, buflen,
- "AMANDA: TAPESTART DATE %s TAPE %s\n014\n",
- file->datestamp, file->name);
+ g_string_printf(rval,
+ "AMANDA: TAPESTART DATE %s TAPE %s\n\014\n",
+ file->datestamp, file->name);
break;
case F_SPLIT_DUMPFILE:
validate_parts(file->partnum, file->totalparts);
- snprintf(split_data, SIZEOF(split_data),
- " part %d/%d ", file->partnum, file->totalparts);
- /*FALLTHROUGH*/
-
+ g_string_printf(split_data,
+ " part %d/%d ", file->partnum, file->totalparts);
+ /* FALLTHROUGH */
+
case F_CONT_DUMPFILE:
case F_DUMPFILE :
- validate_name(file->name);
+ validate_nonempty_str(file->name, "name");
+ validate_nonempty_str(file->program, "program");
validate_datestamp(file->datestamp);
+ validate_encrypt_suffix(file->encrypted, file->encrypt_suffix);
qname = quote_string(file->disk);
- n = snprintf(buffer, buflen,
- "AMANDA: %s %s %s %s %s lev %d comp %s program %s",
- filetype2str(file->type),
- file->datestamp, file->name, qname,
- split_data,
- file->dumplevel, file->comp_suffix, file->program);
- amfree(qname);
- if ( n ) {
- buffer += n;
- buflen -= n;
- n = 0;
+ program = stralloc(file->program);
+ if (match("^.*[.][Ee][Xx][Ee]$", program)) {
+ /* Trim ".exe" from program name */
+ program[strlen(program) - strlen(".exe")] = '\0';
}
-
- if (strcmp(file->encrypt_suffix, "enc") == 0) { /* only output crypt if it's enabled */
- n = snprintf(buffer, buflen, " crypt %s", file->encrypt_suffix);
- }
- if ( n ) {
- buffer += n;
- buflen -= n;
- n = 0;
+ g_string_printf(rval,
+ "AMANDA: %s %s %s %s %s lev %d comp %s program %s",
+ filetype2str(file->type),
+ file->datestamp, file->name, qname,
+ split_data->str,
+ file->dumplevel,
+ file->compressed? file->comp_suffix : "N",
+ program);
+ amfree(program);
+ amfree(qname);
+
+ /* only output crypt if it's enabled */
+ if (file->encrypted) {
+ g_string_append_printf(rval, " crypt %s", file->encrypt_suffix);
}
+ validate_not_both(file->srvcompprog, file->clntcompprog,
+ "srvcompprog", "clntcompprog");
if (*file->srvcompprog) {
- n = snprintf(buffer, buflen, " server_custom_compress %s", file->srvcompprog);
+ validate_no_space(file->srvcompprog, "srvcompprog");
+ g_string_append_printf(rval, " server_custom_compress %s",
+ file->srvcompprog);
} else if (*file->clntcompprog) {
- n = snprintf(buffer, buflen, " client_custom_compress %s", file->clntcompprog);
- }
-
- if ( n ) {
- buffer += n;
- buflen -= n;
- n = 0;
+ validate_no_space(file->clntcompprog, "clntcompprog");
+ g_string_append_printf(rval, " client_custom_compress %s",
+ file->clntcompprog);
}
+ validate_not_both(file->srv_encrypt, file->clnt_encrypt,
+ "srv_encrypt", "clnt_encrypt");
if (*file->srv_encrypt) {
- n = snprintf(buffer, buflen, " server_encrypt %s", file->srv_encrypt);
+ validate_no_space(file->srv_encrypt, "srv_encrypt");
+ g_string_append_printf(rval, " server_encrypt %s",
+ file->srv_encrypt);
} else if (*file->clnt_encrypt) {
- n = snprintf(buffer, buflen, " client_encrypt %s", file->clnt_encrypt);
- }
-
- if ( n ) {
- buffer += n;
- buflen -= n;
- n = 0;
+ validate_no_space(file->clnt_encrypt, "clnt_encrypt");
+ g_string_append_printf(rval, " client_encrypt %s",
+ file->clnt_encrypt);
}
-
+
+ validate_not_both(file->srv_decrypt_opt, file->clnt_decrypt_opt,
+ "srv_decrypt_opt", "clnt_decrypt_opt");
if (*file->srv_decrypt_opt) {
- n = snprintf(buffer, buflen, " server_decrypt_option %s", file->srv_decrypt_opt);
- } else if (*file->clnt_decrypt_opt) {
- n = snprintf(buffer, buflen, " client_decrypt_option %s", file->clnt_decrypt_opt);
+ validate_no_space(file->srv_decrypt_opt, "srv_decrypt_opt");
+ g_string_append_printf(rval, " server_decrypt_option %s",
+ file->srv_decrypt_opt);
+ } else if (*file->clnt_decrypt_opt) {
+ g_string_append_printf(rval, " client_decrypt_option %s",
+ file->clnt_decrypt_opt);
}
-
- if ( n ) {
- buffer += n;
- buflen -= n;
- n = 0;
- }
-
- n = snprintf(buffer, buflen, "\n");
- buffer += n;
- buflen -= n;
-
+
+ g_string_append_printf(rval, "\n");
+
if (file->cont_filename[0] != '\0') {
- n = snprintf(buffer, buflen, "CONT_FILENAME=%s\n",
- file->cont_filename);
- buffer += n;
- buflen -= n;
+ g_string_append_printf(rval, "CONT_FILENAME=%s\n",
+ file->cont_filename);
+ }
+ if (file->application[0] != '\0') {
+ g_string_append_printf(rval, "APPLICATION=%s\n", file->application);
}
if (file->is_partial != 0) {
- n = snprintf(buffer, buflen, "PARTIAL=YES\n");
- buffer += n;
- buflen -= n;
+ g_string_append_printf(rval, "PARTIAL=YES\n");
+ }
+ if (file->orig_size > 0) {
+ g_string_append_printf(rval, "ORIGSIZE=%jd\n",
+ (intmax_t)file->orig_size);
+ }
+ if (file->dle_str && strlen(file->dle_str) < max_size-2048) {
+ char *heredoc = quote_heredoc(file->dle_str, "ENDDLE");
+ g_string_append_printf(rval, "DLE=%s\n", heredoc);
+ amfree(heredoc);
+ }
+
+ g_string_append_printf(rval,
+ _("To restore, position tape at start of file and run:\n"));
+
+ g_string_append_printf(rval, "\tdd if=<tape> ");
+ if (file->blocksize)
+ g_string_append_printf(rval, "bs=%zuk ",
+ file->blocksize / 1024);
+ g_string_append_printf(rval, "skip=1 | ");
+ if (*file->recover_cmd) {
+ if (*file->decrypt_cmd) {
+ validate_pipe_cmd(file->decrypt_cmd, "decrypt_cmd");
+ g_string_append_printf(rval, "%s ", file->decrypt_cmd);
+ }
+ if (*file->uncompress_cmd) {
+ validate_pipe_cmd(file->uncompress_cmd, "uncompress_cmd");
+ g_string_append_printf(rval, "%s ", file->uncompress_cmd);
+ }
+ g_string_append_printf(rval, "%s ", file->recover_cmd);
+ } else {
+ if (*file->uncompress_cmd || *file->decrypt_cmd)
+ error("cannot specify uncompress_cmd or decrypt_cmd without recover_cmd\n");
}
-
- n = snprintf(buffer, buflen,
- "To restore, position tape at start of file and run:\n");
- buffer += n;
- buflen -= n;
-
/* \014 == ^L == form feed */
- n = snprintf(buffer, buflen,
- "\tdd if=<tape> bs=" SIZE_T_FMT "k skip=1 | %s %s %s\n\014\n",
- (SIZE_T_FMT_TYPE)file->blocksize / 1024, file->decrypt_cmd,
- file->uncompress_cmd, file->recover_cmd);
+ g_string_append_printf(rval, "\n\014\n");
break;
case F_TAPEEND:
validate_datestamp(file->datestamp);
- snprintf(buffer, buflen, "AMANDA: TAPEEND DATE %s\n\014\n",
- file->datestamp);
+ g_string_printf(rval, "AMANDA: TAPEEND DATE %s\n\014\n",
+ file->datestamp);
+ break;
+
+ case F_NOOP:
+ g_string_printf(rval, "AMANDA: NOOP\n\014\n");
break;
case F_UNKNOWN:
case F_EMPTY:
case F_WEIRD:
default:
- error("Invalid header type: %d (%s)",
+ error(_("Invalid header type: %d (%s)"),
file->type, filetype2str(file->type));
/*NOTREACHED*/
}
+
+ g_string_free(split_data, TRUE);
+
+ /* is it too big? */
+ if (rval->len > max_size) {
+ g_debug("header is larger than %zu bytes -- cannot create", max_size);
+ g_string_free(rval, TRUE);
+ return NULL;
+ }
+
+ /* Clear extra bytes. */
+ if (rval->len < min_size) {
+ bzero(rval->str + rval->len, rval->allocated_len - rval->len);
+ }
+ if (size) {
+ *size = MAX(min_size, (size_t)rval->len);
+ }
+ return g_string_free(rval, FALSE);
}
-/*
- * Prints the contents of the file structure.
- */
void
print_header(
FILE * outf,
const dumpfile_t * file)
+{
+ char *summ = summarize_header(file);
+ g_fprintf(outf, "%s\n", summ);
+ g_free(summ);
+}
+
+/*
+ * Prints the contents of the file structure.
+ */
+char *
+summarize_header(
+ const dumpfile_t * file)
{
char *qdisk;
- char number[NUM_STR_SIZE*2];
+ GString *summ;
switch(file->type) {
case F_EMPTY:
- fprintf(outf, "EMPTY file\n");
- break;
+ return g_strdup(_("EMPTY file"));
case F_UNKNOWN:
- fprintf(outf, "UNKNOWN file\n");
- break;
+ return g_strdup(_("UNKNOWN file"));
+ default:
case F_WEIRD:
- fprintf(outf, "WEIRD file\n");
- break;
+ return g_strdup(_("WEIRD file"));
case F_TAPESTART:
- fprintf(outf, "start of tape: date %s label %s\n",
+ return g_strdup_printf(_("start of tape: date %s label %s"),
file->datestamp, file->name);
- break;
+
+ case F_NOOP:
+ return g_strdup(_("NOOP file"));
case F_DUMPFILE:
case F_CONT_DUMPFILE:
qdisk = quote_string(file->disk);
- fprintf(outf, "%s: date %s host %s disk %s lev %d comp %s",
+ summ = g_string_new("");
+ g_string_printf(summ, "%s: date %s host %s disk %s lev %d comp %s",
filetype2str(file->type), file->datestamp, file->name,
- qdisk, file->dumplevel, file->comp_suffix);
- if (*file->program)
- fprintf(outf, " program %s",file->program);
- if (strcmp(file->encrypt_suffix, "enc") == 0)
- fprintf(outf, " crypt %s", file->encrypt_suffix);
- if (*file->srvcompprog)
- fprintf(outf, " server_custom_compress %s", file->srvcompprog);
- if (*file->clntcompprog)
- fprintf(outf, " client_custom_compress %s", file->clntcompprog);
- if (*file->srv_encrypt)
- fprintf(outf, " server_encrypt %s", file->srv_encrypt);
- if (*file->clnt_encrypt)
- fprintf(outf, " client_encrypt %s", file->clnt_encrypt);
- if (*file->srv_decrypt_opt)
- fprintf(outf, " server_decrypt_option %s", file->srv_decrypt_opt);
- if (*file->clnt_decrypt_opt)
- fprintf(outf, " client_decrypt_option %s", file->clnt_decrypt_opt);
- fprintf(outf, "\n");
+ qdisk, file->dumplevel,
+ file->compressed? file->comp_suffix : "N");
amfree(qdisk);
- break;
-
- case F_SPLIT_DUMPFILE:
- if(file->totalparts > 0){
- snprintf(number, SIZEOF(number), "%d", file->totalparts);
- }
- else snprintf(number, SIZEOF(number), "UNKNOWN");
+ goto add_suffixes;
+
+ case F_SPLIT_DUMPFILE: {
+ char totalparts[NUM_STR_SIZE*2];
+ if(file->totalparts > 0)
+ g_snprintf(totalparts, SIZEOF(totalparts), "%d", file->totalparts);
+ else
+ g_snprintf(totalparts, SIZEOF(totalparts), "UNKNOWN");
qdisk = quote_string(file->disk);
- fprintf(outf, "split dumpfile: date %s host %s disk %s part %d/%s lev %d comp %s",
+ summ = g_string_new("");
+ g_string_printf(summ, "split dumpfile: date %s host %s disk %s"
+ " part %d/%s lev %d comp %s",
file->datestamp, file->name, qdisk, file->partnum,
- number, file->dumplevel, file->comp_suffix);
- if (*file->program)
- fprintf(outf, " program %s",file->program);
+ totalparts, file->dumplevel,
+ file->compressed? file->comp_suffix : "N");
+ amfree(qdisk);
+ goto add_suffixes;
+ }
+
+ add_suffixes:
+ if (*file->program)
+ g_string_append_printf(summ, " program %s", file->program);
if (strcmp(file->encrypt_suffix, "enc") == 0)
- fprintf(outf, " crypt %s", file->encrypt_suffix);
+ g_string_append_printf(summ, " crypt %s", file->encrypt_suffix);
if (*file->srvcompprog)
- fprintf(outf, " server_custom_compress %s", file->srvcompprog);
+ g_string_append_printf(summ, " server_custom_compress %s", file->srvcompprog);
if (*file->clntcompprog)
- fprintf(outf, " client_custom_compress %s", file->clntcompprog);
+ g_string_append_printf(summ, " client_custom_compress %s", file->clntcompprog);
if (*file->srv_encrypt)
- fprintf(outf, " server_encrypt %s", file->srv_encrypt);
+ g_string_append_printf(summ, " server_encrypt %s", file->srv_encrypt);
if (*file->clnt_encrypt)
- fprintf(outf, " client_encrypt %s", file->clnt_encrypt);
+ g_string_append_printf(summ, " client_encrypt %s", file->clnt_encrypt);
if (*file->srv_decrypt_opt)
- fprintf(outf, " server_decrypt_option %s", file->srv_decrypt_opt);
+ g_string_append_printf(summ, " server_decrypt_option %s", file->srv_decrypt_opt);
if (*file->clnt_decrypt_opt)
- fprintf(outf, " client_decrypt_option %s", file->clnt_decrypt_opt);
- fprintf(outf, "\n");
- amfree(qdisk);
- break;
+ g_string_append_printf(summ, " client_decrypt_option %s", file->clnt_decrypt_opt);
+ return g_string_free(summ, FALSE);
case F_TAPEEND:
- fprintf(outf, "end of tape: date %s\n", file->datestamp);
+ return g_strdup_printf("end of tape: date %s", file->datestamp);
break;
}
}
{ F_TAPEEND, "TAPEEND" },
{ F_DUMPFILE, "FILE" },
{ F_CONT_DUMPFILE, "CONT_FILE" },
- { F_SPLIT_DUMPFILE, "SPLIT_FILE" }
+ { F_SPLIT_DUMPFILE, "SPLIT_FILE" },
+ { F_NOOP, "NOOP" }
};
#define NFILETYPES (size_t)(sizeof(filetypetab) / sizeof(filetypetab[0]))
return (filetypetab[i].type);
return (F_UNKNOWN);
}
+
+gboolean headers_are_equal(dumpfile_t * a, dumpfile_t * b) {
+ if (a == NULL && b == NULL)
+ return TRUE;
+
+ if (a == NULL || b == NULL)
+ return FALSE;
+
+ if (a->type != b->type) return FALSE;
+ if (strcmp(a->datestamp, b->datestamp)) return FALSE;
+ if (a->dumplevel != b->dumplevel) return FALSE;
+ if (a->compressed != b->compressed) return FALSE;
+ if (a->encrypted != b->encrypted) return FALSE;
+ if (strcmp(a->comp_suffix, b->comp_suffix)) return FALSE;
+ if (strcmp(a->encrypt_suffix, b->encrypt_suffix)) return FALSE;
+ if (strcmp(a->name, b->name)) return FALSE;
+ if (strcmp(a->disk, b->disk)) return FALSE;
+ if (strcmp(a->program, b->program)) return FALSE;
+ if (strcmp(a->application, b->application)) return FALSE;
+ if (strcmp(a->srvcompprog, b->srvcompprog)) return FALSE;
+ if (strcmp(a->clntcompprog, b->clntcompprog)) return FALSE;
+ if (strcmp(a->srv_encrypt, b->srv_encrypt)) return FALSE;
+ if (strcmp(a->clnt_encrypt, b->clnt_encrypt)) return FALSE;
+ if (strcmp(a->recover_cmd, b->recover_cmd)) return FALSE;
+ if (strcmp(a->uncompress_cmd, b->uncompress_cmd)) return FALSE;
+ if (strcmp(a->decrypt_cmd, b->decrypt_cmd)) return FALSE;
+ if (strcmp(a->srv_decrypt_opt, b->srv_decrypt_opt)) return FALSE;
+ if (strcmp(a->clnt_decrypt_opt, b->clnt_decrypt_opt)) return FALSE;
+ if (strcmp(a->cont_filename, b->cont_filename)) return FALSE;
+ if (a->dle_str != b->dle_str && a->dle_str && b->dle_str
+ && strcmp(a->dle_str, b->dle_str)) return FALSE;
+ if (a->is_partial != b->is_partial) return FALSE;
+ if (a->partnum != b->partnum) return FALSE;
+ if (a->totalparts != b->totalparts) return FALSE;
+ if (a->blocksize != b->blocksize) return FALSE;
+
+ return TRUE; /* ok, they're the same */
+}
+
+dumpfile_t * dumpfile_copy(dumpfile_t* source) {
+ dumpfile_t* rval = malloc(sizeof(dumpfile_t));
+ memcpy(rval, source, sizeof(dumpfile_t));
+ if (rval->dle_str) rval->dle_str = stralloc(rval->dle_str);
+ return rval;
+}
+
+void
+dumpfile_copy_in_place(
+ dumpfile_t *dest,
+ dumpfile_t* source)
+{
+ memcpy(dest, source, sizeof(dumpfile_t));
+ if (dest->dle_str) dest->dle_str = stralloc(dest->dle_str);
+}
+
+void dumpfile_free_data(dumpfile_t* info) {
+ if (info) {
+ amfree(info->dle_str);
+ }
+}
+
+void dumpfile_free(dumpfile_t* info) {
+ dumpfile_free_data(info);
+ amfree(info);
+}
+
+static char *quote_heredoc(
+ char *text,
+ char *delimiter_prefix)
+{
+ char *delimiter = stralloc(delimiter_prefix);
+ int delimiter_n = 0;
+ int delimiter_len = strlen(delimiter);
+ char *quoted;
+
+ /* keep picking delimiters until we find one that's not a line in TEXT */
+ while (1) {
+ char *line = text;
+ char *c = text;
+ gboolean found_delimiter = FALSE;
+
+ while (1) {
+ if (*c == '\n' || *c == '\0') {
+ int linelen = c - line;
+ if (linelen == delimiter_len && 0 == strncmp(line, delimiter, linelen)) {
+ found_delimiter = TRUE;
+ break;
+ }
+ line = c+1;
+ }
+ if (!*c) break;
+ c++;
+ }
+
+ if (!found_delimiter)
+ break;
+
+ delimiter = newvstrallocf(delimiter, "%s%d", delimiter_prefix, ++delimiter_n);
+ delimiter_len = strlen(delimiter);
+ }
+
+ /* we have a delimiter .. now use it */
+ quoted = vstrallocf("<<%s\n%s\n%s", delimiter, text, delimiter);
+ amfree(delimiter);
+ return quoted;
+}
+
+static char *parse_heredoc(
+ char *line,
+ char **saveptr)
+{
+ char *result = NULL;
+
+ if (strncmp(line, "<<", 2) == 0) {
+ char *keyword = line+2;
+ char *new_line;
+
+ while((new_line = strtok_r(NULL, "\n", saveptr)) != NULL &&
+ strcmp(new_line, keyword) != 0) {
+ result = vstrextend(&result, new_line, "\n", NULL);
+ }
+ /* make sure we have something */
+ if (!result)
+ result = g_strdup("");
+ /* remove latest '\n' */
+ else if (strlen(result) > 0)
+ result[strlen(result)-1] = '\0';
+ } else {
+ result = stralloc(line);
+ }
+ return result;
+}