Beispiel #1
0
/*
 * Convert a previously str-ified and escaped list of tapes back into a
 * tapelist structure.
 */
tapelist_t *
unmarshal_tapelist_str(
    char *	tapelist_str,
    int		with_storage)
{
    char *temp_storage, *temp_label, *temp_filenum;
    int l_idx, n_idx;
    size_t input_length;
    tapelist_t *tapelist = NULL;

    if(!tapelist_str) return(NULL);

    input_length = strlen(tapelist_str);

    temp_label = g_malloc(input_length+1);
    temp_storage = g_malloc(input_length+1);
    temp_filenum = g_malloc(input_length+1);

    do {
	/* first, read the storage part */
	if (with_storage) {
	    memset(temp_storage, '\0', input_length+1);
            l_idx = 0;
	    while(*tapelist_str != ':' && *tapelist_str != '\0'){
		if(*tapelist_str == '\\')
		    tapelist_str++; /* skip escapes */
		temp_storage[l_idx] = *tapelist_str;
		if(*tapelist_str == '\0')
		    break; /* bad format, should kvetch */
		tapelist_str++;
		l_idx++;
	    }
	    if(*tapelist_str != '\0')
		tapelist_str++;
	}

	/* then, read the label part */
	memset(temp_label, '\0', input_length+1);
        l_idx = 0;
	while(*tapelist_str != ':' && *tapelist_str != '\0'){
	    if(*tapelist_str == '\\')
		tapelist_str++; /* skip escapes */
	    temp_label[l_idx] = *tapelist_str;
	    if(*tapelist_str == '\0')
		break; /* bad format, should kvetch */
	    tapelist_str++;
	    l_idx++;
	}
	if(*tapelist_str != '\0')
	    tapelist_str++;
	tapelist = append_to_tapelist(tapelist, temp_storage, temp_label, (off_t)-1, -1, 0);

	/* now read the list of file numbers */
	while(*tapelist_str != ';' && *tapelist_str != '\0'){
	    off_t filenum;

	    memset(temp_filenum, '\0', input_length+1);
	    n_idx = 0;
	    while(*tapelist_str != ';' && *tapelist_str != ',' &&
		    *tapelist_str != '\0'){
		temp_filenum[n_idx] = *tapelist_str; 
		tapelist_str++;
		n_idx++;
	    }
	    filenum = OFF_T_ATOI(temp_filenum);

	    tapelist = append_to_tapelist(tapelist, temp_storage, temp_label, filenum, -1, 0);
	    if(*tapelist_str != '\0' && *tapelist_str != ';')
		tapelist_str++;
	}
	if(*tapelist_str != '\0')
	    tapelist_str++;

    } while(*tapelist_str != '\0');

    amfree(temp_label);
    amfree(temp_storage);
    amfree(temp_filenum);

    return(tapelist);
}
Beispiel #2
0
/*
 * Write out the buffer to the backing file
 */
static int
databuf_flush(
    struct databuf *	db)
{
    struct cmdargs *cmdargs = NULL;
    int rc = 1;
    size_t size_to_write;
    size_t written;
    off_t left_in_chunk;
    char *arg_filename = NULL;
    char *new_filename = NULL;
    char *tmp_filename = NULL;
    char sequence[NUM_STR_SIZE];
    int newfd;
    filetype_t save_type;
    char *q;
    int a;
    char *pc;

    /*
     * If there's no data, do nothing.
     */
    if (db->dataout >= db->datain) {
        goto common_exit;
    }

    /*
     * See if we need to split this file.
     */
    while (db->split_size > (off_t)0 && dumpsize >= db->split_size) {
        if( db->use == (off_t)0 ) {
            /*
             * Probably no more space on this disk.  Request some more.
             */
            putresult(RQ_MORE_DISK, "%s\n", handle);
            cmdargs = getcmd();
            if(command_in_transit == NULL &&
                    (cmdargs->cmd == DONE || cmdargs->cmd == TRYAGAIN || cmdargs->cmd == FAILED)) {
                command_in_transit = cmdargs;
                cmdargs = getcmd();
            }
            if(cmdargs->cmd == CONTINUE) {
                /*
                 * CONTINUE
                 *   serial
                 *   filename
                 *   chunksize
                 *   use
                 */
                a = 2; /* skip CONTINUE and serial */

                if(a >= cmdargs->argc) {
                    error(_("error [chunker CONTINUE: not enough args: filename]"));
                    /*NOTREACHED*/
                }
                arg_filename = newstralloc(arg_filename, cmdargs->argv[a++]);

                if(a >= cmdargs->argc) {
                    error(_("error [chunker CONTINUE: not enough args: chunksize]"));
                    /*NOTREACHED*/
                }
                db->chunk_size = OFF_T_ATOI(cmdargs->argv[a++]);
                db->chunk_size = am_floor(db->chunk_size, (off_t)DISK_BLOCK_KB);

                if(a >= cmdargs->argc) {
                    error(_("error [chunker CONTINUE: not enough args: use]"));
                    /*NOTREACHED*/
                }
                db->use = OFF_T_ATOI(cmdargs->argv[a++]);

                if(a != cmdargs->argc) {
                    error(_("error [chunker CONTINUE: too many args: %d != %d]"),
                          cmdargs->argc, a);
                    /*NOTREACHED*/
                }

                if(strcmp(db->filename, arg_filename) == 0) {
                    /*
                     * Same disk, so use what room is left up to the
                     * next chunk boundary or the amount we were given,
                     * whichever is less.
                     */
                    left_in_chunk = db->chunk_size - filesize;
                    if(left_in_chunk > db->use) {
                        db->split_size += db->use;
                        db->use = (off_t)0;
                    } else {
                        db->split_size += left_in_chunk;
                        db->use -= left_in_chunk;
                    }
                    if(left_in_chunk > (off_t)0) {
                        /*
                         * We still have space in this chunk.
                         */
                        break;
                    }
                } else {
                    /*
                     * Different disk, so use new file.
                     */
                    db->filename = newstralloc(db->filename, arg_filename);
                }
            } else if(cmdargs->cmd == ABORT) {
                abort_pending = 1;
                errstr = newstralloc(errstr, cmdargs->argv[1]);
                putresult(ABORT_FINISHED, "%s\n", handle);
                rc = 0;
                goto common_exit;
            } else {
                if(cmdargs->argc >= 1) {
                    q = quote_string(cmdargs->argv[0]);
                } else {
                    q = stralloc(_("(no input?)"));
                }
                error(_("error [bad command after RQ-MORE-DISK: \"%s\"]"), q);
                /*NOTREACHED*/
            }
        }

        /*
         * Time to use another file.
         */

        /*
         * First, open the new chunk file, and give it a new header
         * that has no cont_filename pointer.
         */
        g_snprintf(sequence, SIZEOF(sequence), "%d", db->filename_seq);
        new_filename = newvstralloc(new_filename,
                                    db->filename,
                                    ".",
                                    sequence,
                                    NULL);
        tmp_filename = newvstralloc(tmp_filename,
                                    new_filename,
                                    ".tmp",
                                    NULL);
        pc = strrchr(tmp_filename, '/');
        g_assert(pc != NULL); /* Only a problem if db->filename has no /. */
        *pc = '\0';
        mkholdingdir(tmp_filename);
        *pc = '/';
        newfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
        if (newfd == -1) {
            int save_errno = errno;
            char *m;

            if(save_errno == ENOSPC) {
                putresult(NO_ROOM, "%s %lld\n", handle,
                          (long long)(db->use+db->split_size-dumpsize));
                db->use = (off_t)0;			/* force RQ_MORE_DISK */
                db->split_size = dumpsize;
                continue;
            }
            m = vstrallocf(_("creating chunk holding file \"%s\": %s"),
                           tmp_filename,
                           strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            aclose(db->fd);
            rc = 0;
            goto common_exit;
        }
        save_type = file.type;
        file.type = F_CONT_DUMPFILE;
        file.cont_filename[0] = '\0';
        if(write_tapeheader(newfd, &file)) {
            int save_errno = errno;
            char *m;

            aclose(newfd);
            if(save_errno == ENOSPC) {
                putresult(NO_ROOM, "%s %lld\n", handle,
                          (long long)(db->use+db->split_size-dumpsize));
                db->use = (off_t)0;			/* force RQ_MORE DISK */
                db->split_size = dumpsize;
                continue;
            }
            m = vstrallocf(_("write_tapeheader file %s: %s"),
                           tmp_filename,
                           strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            rc = 0;
            goto common_exit;
        }

        /*
         * Now, update the header of the current file to point
         * to the next chunk, and then close it.
         */
        if (lseek(db->fd, (off_t)0, SEEK_SET) < (off_t)0) {
            char *m = vstrallocf(_("lseek holding file %s: %s"),
                                 db->filename,
                                 strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            aclose(newfd);
            rc = 0;
            goto common_exit;
        }

        file.type = save_type;
        strncpy(file.cont_filename, new_filename, SIZEOF(file.cont_filename));
        file.cont_filename[SIZEOF(file.cont_filename)-1] = '\0';
        if(write_tapeheader(db->fd, &file)) {
            char * m = vstrallocf(_("write_tapeheader file \"%s\": %s"),
                                  db->filename,
                                  strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            aclose(newfd);
            unlink(tmp_filename);
            rc = 0;
            goto common_exit;
        }
        file.type = F_CONT_DUMPFILE;

        /*
         * Now shift the file descriptor.
         */
        aclose(db->fd);
        db->fd = newfd;
        newfd = -1;

        /*
         * Update when we need to chunk again
         */
        if(db->use <= (off_t)DISK_BLOCK_KB) {
            /*
             * Cheat and use one more block than allowed so we can make
             * some progress.
             */
            db->split_size += (off_t)(2 * DISK_BLOCK_KB);
            db->use = (off_t)0;
        } else if(db->chunk_size > db->use) {
            db->split_size += db->use;
            db->use = (off_t)0;
        } else {
            db->split_size += db->chunk_size;
            db->use -= db->chunk_size;
        }


        amfree(tmp_filename);
        amfree(new_filename);
        dumpsize += (off_t)DISK_BLOCK_KB;
        filesize = (off_t)DISK_BLOCK_KB;
        headersize += DISK_BLOCK_KB;
        db->filename_seq++;
    }

    /*
     * Write out the buffer
     */
    size_to_write = (size_t)(db->datain - db->dataout);
    written = full_write(db->fd, db->dataout, size_to_write);
    if (written > 0) {
        db->dataout += written;
        dumpbytes += (off_t)written;
    }
    dumpsize += (dumpbytes / (off_t)1024);
    filesize += (dumpbytes / (off_t)1024);
    dumpbytes %= 1024;
    if (written < size_to_write) {
        if (errno != ENOSPC) {
            char *m = vstrallocf(_("data write: %s"), strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            rc = 0;
            goto common_exit;
        }

        /*
         * NO-ROOM is informational only.  Later, RQ_MORE_DISK will be
         * issued to use another holding disk.
         */
        putresult(NO_ROOM, "%s %lld\n", handle,
                  (long long)(db->use+db->split_size-dumpsize));
        db->use = (off_t)0;				/* force RQ_MORE_DISK */
        db->split_size = dumpsize;
        goto common_exit;
    }
    if (db->datain == db->dataout) {
        /*
         * We flushed the whole buffer so reset to use it all.
         */
        db->datain = db->dataout = db->buf;
    }

common_exit:

    if (cmdargs)
        free_cmdargs(cmdargs);
    amfree(new_filename);
    /*@i@*/ amfree(tmp_filename);
    amfree(arg_filename);
    return rc;
}
Beispiel #3
0
void
parse_file_header(
    const char *buffer,
    dumpfile_t *file,
    size_t	buflen)
{
    char *buf, *line, *tok, *line1;
    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 = g_malloc(buflen + 1);
    memcpy(buf, buffer, buflen);
    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)
	    break;

	if (*line == '"') {
	    in_quotes = !in_quotes;
	} else if ((*line == '\\') && (*(line + 1) == '"')) {
	    line++;
	    lsize++;
	}
	lsize++;
    }
    *line = '\0';
    line1 = g_malloc(lsize + 1);
    strncpy(line1, buf, lsize);
    line1[lsize] = '\0';
    *line = '\n';

    tok = strtok_r(line1, " ", &saveptr);
    if (tok == NULL) {
        g_debug("Empty amanda header: buflen=%zu lsize=%zu buf='%s'", buflen, lsize, buf);
	strange_header(file, buffer, buflen, _("<Non-empty line>"), tok);
	goto out;
    }

    if (!g_str_equal(tok, "NETDUMP:") && !g_str_equal(tok, "AMANDA:")) {
	amfree(buf);
	file->type = F_WEIRD;
	amfree(line1);
	return;
    }

    tok = strtok_r(NULL, " ", &saveptr);
    if (tok == NULL) {
	strange_header(file, buffer, buflen, _("<file type>"), tok);
	goto out;
    }
    file->type = str2filetype(tok);
    
    switch (file->type) {
    case F_TAPESTART:
	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "DATE"))) {
	    strange_header(file, buffer, buflen, "DATE", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<date stamp>"), tok);
	    goto out;
	}
	strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
	file->datestamp[sizeof(file->datestamp) - 1] = '\0';

	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "TAPE"))) {
	    strange_header(file, buffer, buflen, "TAPE", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<file type>"), tok);
	    goto out;
	}
	strncpy(file->name, tok, sizeof(file->name) - 1);
	file->name[sizeof(file->name) - 1] = '\0';
	break;

    case F_DUMPFILE:
    case F_CONT_DUMPFILE:
    case F_SPLIT_DUMPFILE:
	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<date stamp>"), tok);
	    goto out;
	}
	strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
	file->datestamp[sizeof(file->datestamp) - 1] = '\0';

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<file name>"), tok);
	    goto out;
	}
	strncpy(file->name, tok, sizeof(file->name) - 1);
	file->name[sizeof(file->name) - 1] = '\0';

	tok = strquotedstr(&saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<disk name>"), tok);
	    goto out;
	}
	uqname = unquote_string(tok);
	strncpy(file->disk, uqname, sizeof(file->disk) - 1);
	file->disk[sizeof(file->disk) - 1] = '\0';
 	amfree(uqname);
	
	if(file->type == F_SPLIT_DUMPFILE) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL || !g_str_equal(tok, "part")) {
		strange_header(file, buffer, buflen, "part", tok);
		goto out;
	    }

	    tok = strtok_r(NULL, "/", &saveptr);
	    if ((tok == NULL) || (sscanf(tok, "%d", &file->partnum) != 1)) {
		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_r(NULL, " ", &saveptr);
            if((tok == NULL) || (sscanf(tok, "%d", &file->totalparts) != 1)) {
		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_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "lev"))) {
	    strange_header(file, buffer, buflen, "lev", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (sscanf(tok, "%d", &file->dumplevel) != 1)) {
	    strange_header(file, buffer, buflen, _("<dump level param>"), tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "comp"))) {
	    strange_header(file, buffer, buflen, "comp", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<comp param>"), tok);
	    goto out;
	}
	strncpy(file->comp_suffix, tok, sizeof(file->comp_suffix) - 1);

	file->compressed = (!g_str_equal(file->comp_suffix, "N"));
	if (file->compressed) {
	    /* compatibility with pre-2.2 amanda */
	    if (g_str_equal(file->comp_suffix, "C"))
		strncpy(file->comp_suffix, ".Z", sizeof(file->comp_suffix) - 1);
	} else {
	    strcpy(file->comp_suffix, "");
	}
	file->comp_suffix[sizeof(file->comp_suffix) - 1] = '\0';

	tok = strtok_r(NULL, " ", &saveptr);
        /* "program" is optional */
        if (tok == NULL || !g_str_equal(tok, "program")) {
	    break;
	}

        tok = strtok_r(NULL, " ", &saveptr);
        if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<program name>"), tok);
	    goto out;
	}
        strncpy(file->program, tok, sizeof(file->program) - 1);
	file->program[sizeof(file->program) - 1] = '\0';

	if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
             break;          /* reached the end of the buffer */

	/* encryption is optional */
	if (BSTRNCMP(tok, "crypt") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen, _("<crypt param>"), tok);
		goto out;
	    }
	    strncpy(file->encrypt_suffix, tok,
		    sizeof(file->encrypt_suffix) - 1);
	    file->encrypt_suffix[sizeof(file->encrypt_suffix) - 1] = '\0';
	    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_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<server custom compress param>"), tok);
		goto out;
	    }
	    strncpy(file->srvcompprog, tok, sizeof(file->srvcompprog) - 1);
	    file->srvcompprog[sizeof(file->srvcompprog) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
		break;      
	}

	/* "clntcompprog" is optional */
	if (BSTRNCMP(tok, "client_custom_compress") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<client custom compress param>"), tok);
		goto out;
	    }
	    strncpy(file->clntcompprog, tok, sizeof(file->clntcompprog) - 1);
	    file->clntcompprog[sizeof(file->clntcompprog) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
		break;
	}

	/* "srv_encrypt" is optional */
	if (BSTRNCMP(tok, "server_encrypt") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<server encrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->srv_encrypt, tok, sizeof(file->srv_encrypt) - 1);
	    file->srv_encrypt[sizeof(file->srv_encrypt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}

	/* "clnt_encrypt" is optional */
	if (BSTRNCMP(tok, "client_encrypt") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<client encrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->clnt_encrypt, tok, sizeof(file->clnt_encrypt) - 1);
	    file->clnt_encrypt[sizeof(file->clnt_encrypt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}

	/* "srv_decrypt_opt" is optional */
	if (BSTRNCMP(tok, "server_decrypt_option") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<server decrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->srv_decrypt_opt, tok,
		    sizeof(file->srv_decrypt_opt) - 1);
	    file->srv_decrypt_opt[sizeof(file->srv_decrypt_opt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}

	/* "clnt_decrypt_opt" is optional */
	if (BSTRNCMP(tok, "client_decrypt_option") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<client decrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->clnt_decrypt_opt, tok,
		    sizeof(file->clnt_decrypt_opt) - 1);
	    file->clnt_decrypt_opt[sizeof(file->clnt_decrypt_opt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}
      break;
      

    case F_TAPEEND:
	tok = strtok_r(NULL, " ", &saveptr);
	/* DATE is optional */
	if (tok != NULL) {
	    if (g_str_equal(tok, "DATE")) {
		tok = strtok_r(NULL, " ", &saveptr);
		if(tok == NULL)
		    file->datestamp[0] = '\0';
		else {
		    strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
		    file->datestamp[sizeof(file->datestamp) - 1] = '\0';
		}
	    } else {
		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|NOOP"), tok);
	goto out;
    }

    (void)strtok_r(buf, "\n", &saveptr); /* this is the first line */
    /* iterate through the rest of the lines */
    while ((line = strtok_r(NULL, "\n", &saveptr)) != NULL) {
#define SC "CONT_FILENAME="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    strncpy(file->cont_filename, line,
		    sizeof(file->cont_filename) - 1);
	    file->cont_filename[sizeof(file->cont_filename) - 1] = '\0';
	    continue;
	}
#undef SC

#define SC "PARTIAL="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    file->is_partial = !strcasecmp(line, "yes");
	    continue;
	}
#undef SC
#define SC "APPLICATION="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    strncpy(file->application, line,
		    sizeof(file->application) - 1);
	    file->application[sizeof(file->application) - 1] = '\0';
	    continue;
	}
#undef SC

#define SC "ORIGSIZE="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    file->orig_size = OFF_T_ATOI(line);
	}
#undef SC

#define SC "DLE="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    amfree(file->dle_str);
	    file->dle_str = parse_heredoc(line, &saveptr);
	}
#undef SC

#define SC _("To restore, position tape at start of file and run:")
	if (g_str_has_prefix(line, SC))
	    continue;
#undef SC

#define SC "\tdd if=<tape> "
	if (g_str_has_prefix(line, SC)) {
	    char *cmd1, *cmd2, *cmd3=NULL;

	    /* skip over dd command */
	    if ((cmd1 = strchr(line, '|')) == NULL) {

	        strncpy(file->recover_cmd, "BUG\0",
		        sizeof(file->recover_cmd) - 1);
	        continue;
	    }
	    *cmd1++ = '\0';

	    /* block out first pipeline command */
	    if ((cmd2 = strchr(cmd1, '|')) != NULL) {
	      *cmd2++ = '\0';
	      if ((cmd3 = strchr(cmd2, '|')) != 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 
	     * XXX could be either uncompress or decrypt. Since no
	     * XXX code actually call uncompress_cmd/decrypt_cmd, it's ok
	     * XXX for header information.
	     * one   cmds: recover
	     */

	    if ( cmd3 == NULL) {
	      if (cmd2 == NULL) {
		strncpy(file->recover_cmd, cmd1,
			sizeof(file->recover_cmd) - 1);
	      } else {
		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 */
	      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);
	    }
	    file->recover_cmd[sizeof(file->recover_cmd) - 1] = '\0';
	    file->uncompress_cmd[sizeof(file->uncompress_cmd) - 1] = '\0';
	    continue;
	}
#undef SC
	/* XXX complain about weird lines? */
    }

out:
    amfree(buf);
    amfree(line1);
}
Beispiel #4
0
int
main(
    int		argc,
    char **	argv)
{
    static struct databuf db;
    struct cmdargs *cmdargs;
    int infd;
    char *q = NULL;
    char *filename = NULL;
    off_t chunksize, use;
    times_t runtime;
    am_feature_t *their_features = NULL;
    int a;
    config_overrides_t *cfg_ovr = NULL;
    char *cfg_opt = NULL;
    char *m;

    /*
     * Configure program for internationalization:
     *   1) Only set the message locale for now.
     *   2) Set textdomain for all amanda related programs to "amanda"
     *      We don't want to be forced to support dozens of message catalogs.
     */
    setlocale(LC_MESSAGES, "C");
    textdomain("amanda");

    safe_fd(-1, 0);

    set_pname("chunker");

    dbopen(DBG_SUBDIR_SERVER);

    /* Don't die when child closes pipe */
    signal(SIGPIPE, SIG_IGN);

    add_amanda_log_handler(amanda_log_stderr);
    add_amanda_log_handler(amanda_log_trace_log);

    cfg_ovr = extract_commandline_config_overrides(&argc, &argv);

    if (argc > 1)
        cfg_opt = argv[1];

    config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
    apply_config_overrides(cfg_ovr);

    if (config_errors(NULL) >= CFGERR_WARNINGS) {
        config_print_errors();
        if (config_errors(NULL) >= CFGERR_ERRORS) {
            g_critical(_("errors processing config file"));
        }
    }

    safe_cd(); /* do this *after* config_init() */

    check_running_as(RUNNING_AS_DUMPUSER);

    dbrename(get_config_name(), DBG_SUBDIR_SERVER);

    log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
    g_fprintf(stderr,
              _("%s: pid %ld executable %s version %s\n"),
              get_pname(), (long) getpid(),
              argv[0], VERSION);
    fflush(stderr);

    /* now, make sure we are a valid user */

    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);

    cmdargs = getcmd();
    if(cmdargs->cmd == START) {
        if(cmdargs->argc <= 1)
            error(_("error [dumper START: not enough args: timestamp]"));
        chunker_timestamp = newstralloc(chunker_timestamp, cmdargs->argv[1]);
    }
    else {
        log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
        error(_("Didn't get START command"));
    }

    /*    do {*/
    cmdargs = getcmd();

    switch(cmdargs->cmd) {
    case QUIT:
        break;

    case PORT_WRITE:
        /*
         * PORT-WRITE
         *   handle
         *   filename
         *   host
         *   features
         *   disk
         *   level
         *   dumpdate
         *   chunksize
         *   progname
         *   use
         *   options
         */
        a = 1;

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: handle]"));
            /*NOTREACHED*/
        }
        handle = newstralloc(handle, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: filename]"));
            /*NOTREACHED*/
        }
        filename = newstralloc(filename, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: hostname]"));
            /*NOTREACHED*/
        }
        hostname = newstralloc(hostname, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: features]"));
            /*NOTREACHED*/
        }
        am_release_feature_set(their_features);
        their_features = am_string_to_feature(cmdargs->argv[a++]);
        if (!their_features) {
            error(_("error [chunker PORT-WRITE: invalid feature string]"));
            /*NOTREACHED*/
        }

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: diskname]"));
            /*NOTREACHED*/
        }
        diskname = newstralloc(diskname, cmdargs->argv[a++]);
        if (qdiskname)
            amfree(qdiskname);
        qdiskname = quote_string(diskname); /* qdiskname is a global */

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: level]"));
            /*NOTREACHED*/
        }
        level = atoi(cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: dumpdate]"));
            /*NOTREACHED*/
        }
        dumpdate = newstralloc(dumpdate, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: chunksize]"));
            /*NOTREACHED*/
        }
        chunksize = OFF_T_ATOI(cmdargs->argv[a++]);
        chunksize = am_floor(chunksize, (off_t)DISK_BLOCK_KB);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: progname]"));
            /*NOTREACHED*/
        }
        progname = newstralloc(progname, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: use]"));
            /*NOTREACHED*/
        }
        use = am_floor(OFF_T_ATOI(cmdargs->argv[a++]), DISK_BLOCK_KB);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: options]"));
            /*NOTREACHED*/
        }
        options = newstralloc(options, cmdargs->argv[a++]);

        if(a != cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: too many args: %d != %d]"),
                  cmdargs->argc, a);
            /*NOTREACHED*/
        }

        if((infd = startup_chunker(filename, use, chunksize, &db)) < 0) {
            q = quote_string(vstrallocf(_("[chunker startup failed: %s]"), errstr));
            putresult(TRYAGAIN, "%s %s\n", handle, q);
            error("startup_chunker failed: %s", errstr);
        }
        command_in_transit = NULL;
        if(infd >= 0 && do_chunk(infd, &db)) {
            char kb_str[NUM_STR_SIZE];
            char kps_str[NUM_STR_SIZE];
            double rt;

            runtime = stopclock();
            rt = g_timeval_to_double(runtime);
            g_snprintf(kb_str, SIZEOF(kb_str), "%lld",
                       (long long)(dumpsize - (off_t)headersize));
            g_snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
                       isnormal(rt) ? (double)dumpsize / rt : 0.0);
            errstr = newvstrallocf(errstr, "sec %s kb %s kps %s",
                                   walltime_str(runtime), kb_str, kps_str);
            m = vstrallocf("[%s]", errstr);
            q = quote_string(m);
            amfree(m);
            if(command_in_transit != NULL) {
                cmdargs = command_in_transit;
                command_in_transit = NULL;
            } else {
                cmdargs = getcmd();
            }
            switch(cmdargs->cmd) {
            case DONE:
                putresult(DONE, "%s %lld %s\n", handle,
                          (long long)(dumpsize - (off_t)headersize), q);
                log_add(L_SUCCESS, "%s %s %s %d [%s]",
                        hostname, qdiskname, chunker_timestamp, level, errstr);
                break;
            case BOGUS:
            case TRYAGAIN:
            case FAILED:
            case ABORT_FINISHED:
                if(dumpsize > (off_t)DISK_BLOCK_KB) {
                    putresult(PARTIAL, "%s %lld %s\n", handle,
                              (long long)(dumpsize - (off_t)headersize),
                              q);
                    log_add(L_PARTIAL, "%s %s %s %d [%s]",
                            hostname, qdiskname, chunker_timestamp, level, errstr);
                }
                else {
                    errstr = newvstrallocf(errstr,
                                           _("dumper returned %s"), cmdstr[cmdargs->cmd]);
                    amfree(q);
                    m = vstrallocf("[%s]",errstr);
                    q = quote_string(m);
                    amfree(m);
                    putresult(FAILED, "%s %s\n", handle, q);
                    log_add(L_FAIL, "%s %s %s %d [%s]",
                            hostname, qdiskname, chunker_timestamp, level, errstr);
                }
            default:
                break;
            }
            amfree(q);
        } else if(infd != -2) {
            if(q == NULL) {
                m = vstrallocf("[%s]", errstr);
                q = quote_string(m);
                amfree(m);
            }
            if(!abort_pending) {
                putresult(FAILED, "%s %s\n", handle, q);
            }
            log_add(L_FAIL, "%s %s %s %d [%s]",
                    hostname, qdiskname, chunker_timestamp, level, errstr);
            amfree(q);
        }
        amfree(filename);
        amfree(db.filename);
        break;

    default:
        if(cmdargs->argc >= 1) {
            q = quote_string(cmdargs->argv[0]);
        } else {
            q = stralloc(_("(no input?)"));
        }
        putresult(BAD_COMMAND, "%s\n", q);
        amfree(q);
        break;
    }

    /*    } while(cmdargs->cmd != QUIT); */

    log_add(L_INFO, "pid-done %ld", (long)getpid());

    amfree(errstr);
    amfree(chunker_timestamp);
    amfree(handle);
    amfree(hostname);
    amfree(diskname);
    amfree(qdiskname);
    amfree(dumpdate);
    amfree(progname);
    amfree(options);
    free_cmdargs(cmdargs);
    if (command_in_transit)
        free_cmdargs(command_in_transit);
    am_release_feature_set(their_features);
    their_features = NULL;

    dbclose();

    return (0); /* exit */
}