#include "protocol.h"
#include "security.h"
#include "stream.h"
-#include "token.h"
#include "version.h"
#include "fileheader.h"
#include "amfeatures.h"
static char *progname = NULL;
static int level;
static char *dumpdate = NULL;
-static int command_in_transit;
+static struct cmdargs *command_in_transit = NULL;
static char *chunker_timestamp = NULL;
static dumpfile_t file;
char ** argv)
{
static struct databuf db;
- struct cmdargs cmdargs;
- cmd_t cmd;
+ struct cmdargs *cmdargs;
int infd;
char *q = NULL;
char *filename = NULL;
- char *qfilename = NULL;
off_t chunksize, use;
times_t runtime;
am_feature_t *their_features = NULL;
int a;
config_overwrites_t *cfg_ovr = NULL;
char *cfg_opt = NULL;
+ char *m;
/*
* Configure program for internationalization:
if (argc > 1)
cfg_opt = argv[1];
- config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD | CONFIG_INIT_FATAL,
- cfg_opt);
+ config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
apply_config_overwrites(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(config_name, DBG_SUBDIR_SERVER);
+ 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(),
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
- cmd = getcmd(&cmdargs);
- if(cmd == START) {
- if(cmdargs.argc <= 1)
+ 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[2]);
+ 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 {*/
- cmd = getcmd(&cmdargs);
+ cmdargs = getcmd();
- switch(cmd) {
+ switch(cmdargs->cmd) {
case QUIT:
break;
* use
* options
*/
- cmdargs.argc++; /* true count of args */
- a = 2;
+ a = 1;
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: handle]"));
/*NOTREACHED*/
}
- handle = newstralloc(handle, cmdargs.argv[a++]);
+ handle = newstralloc(handle, cmdargs->argv[a++]);
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: filename]"));
/*NOTREACHED*/
}
- qfilename = newstralloc(qfilename, cmdargs.argv[a++]);
- if (filename != NULL)
- amfree(filename);
- filename = unquote_string(qfilename);
- amfree(qfilename);
+ filename = newstralloc(filename, cmdargs->argv[a++]);
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: hostname]"));
/*NOTREACHED*/
}
- hostname = newstralloc(hostname, cmdargs.argv[a++]);
+ hostname = newstralloc(hostname, cmdargs->argv[a++]);
- if(a >= cmdargs.argc) {
+ 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++]);
+ 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) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: diskname]"));
/*NOTREACHED*/
}
- qdiskname = newstralloc(qdiskname, cmdargs.argv[a++]);
- if (diskname != NULL)
- amfree(diskname);
- diskname = unquote_string(qdiskname);
+ diskname = newstralloc(diskname, cmdargs->argv[a++]);
+ if (qdiskname)
+ amfree(qdiskname);
+ qdiskname = quote_string(diskname); /* qdiskname is a global */
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: level]"));
/*NOTREACHED*/
}
- level = atoi(cmdargs.argv[a++]);
+ level = atoi(cmdargs->argv[a++]);
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: dumpdate]"));
/*NOTREACHED*/
}
- dumpdate = newstralloc(dumpdate, cmdargs.argv[a++]);
+ dumpdate = newstralloc(dumpdate, cmdargs->argv[a++]);
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: chunksize]"));
/*NOTREACHED*/
}
- chunksize = OFF_T_ATOI(cmdargs.argv[a++]);
+ chunksize = OFF_T_ATOI(cmdargs->argv[a++]);
chunksize = am_floor(chunksize, (off_t)DISK_BLOCK_KB);
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: progname]"));
/*NOTREACHED*/
}
- progname = newstralloc(progname, cmdargs.argv[a++]);
+ progname = newstralloc(progname, cmdargs->argv[a++]);
- if(a >= cmdargs.argc) {
+ 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);
+ use = am_floor(OFF_T_ATOI(cmdargs->argv[a++]), DISK_BLOCK_KB);
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker PORT-WRITE: not enough args: options]"));
/*NOTREACHED*/
}
- options = newstralloc(options, cmdargs.argv[a++]);
+ options = newstralloc(options, cmdargs->argv[a++]);
- if(a != cmdargs.argc) {
+ if(a != cmdargs->argc) {
error(_("error [chunker PORT-WRITE: too many args: %d != %d]"),
- cmdargs.argc, a);
+ cmdargs->argc, a);
/*NOTREACHED*/
}
if((infd = startup_chunker(filename, use, chunksize, &db)) < 0) {
- q = squotef(_("[chunker startup failed: %s]"), errstr);
+ q = quote_string(vstrallocf(_("[chunker startup failed: %s]"), errstr));
putresult(TRYAGAIN, "%s %s\n", handle, q);
- error("startup_chunker failed");
+ error("startup_chunker failed: %s", errstr);
}
- command_in_transit = -1;
+ command_in_transit = NULL;
if(infd >= 0 && do_chunk(infd, &db)) {
char kb_str[NUM_STR_SIZE];
char kps_str[NUM_STR_SIZE];
isnormal(rt) ? (double)dumpsize / rt : 0.0);
errstr = newvstrallocf(errstr, "sec %s kb %s kps %s",
walltime_str(runtime), kb_str, kps_str);
- q = squotef("[%s]", errstr);
- if(command_in_transit != -1)
- cmd = command_in_transit;
- else
- cmd = getcmd(&cmdargs);
- switch(cmd) {
+ 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);
}
else {
errstr = newvstrallocf(errstr,
- _("dumper returned %s"), cmdstr[cmd]);
+ _("dumper returned %s"), cmdstr[cmdargs->cmd]);
amfree(q);
- q = squotef("[%s]",errstr);
+ 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);
}
amfree(q);
} else if(infd != -2) {
+ if(q == NULL) {
+ m = vstrallocf("[%s]", errstr);
+ q = quote_string(m);
+ amfree(m);
+ }
if(!abort_pending) {
- if(q == NULL) {
- q = squotef("[%s]", errstr);
- }
putresult(FAILED, "%s %s\n", handle, q);
- log_add(L_FAIL, "%s %s %s %d [%s]",
- hostname, qdiskname, chunker_timestamp, level, errstr);
- amfree(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 = squote(cmdargs.argv[1]);
- } else if(cmdargs.argc >= 0) {
- q = squote(cmdargs.argv[0]);
+ if(cmdargs->argc >= 1) {
+ q = quote_string(cmdargs->argv[0]);
} else {
q = stralloc(_("(no input?)"));
}
break;
}
-/* } while(cmd != QUIT); */
+/* } while(cmdargs->cmd != QUIT); */
+
+ log_add(L_INFO, "pid-done %ld", (long)getpid());
amfree(errstr);
amfree(chunker_timestamp);
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;
}
data_socket = stream_server(res->ai_family, &data_port, 0,
STREAM_BUFSIZE, 0);
+ if (res) freeaddrinfo(res);
if(data_socket < 0) {
errstr = vstrallocf(_("error creating stream server: %s"), strerror(errno));
putresult(PORT, "%d\n", data_port);
infd = stream_accept(data_socket, CONNECT_TIMEOUT, 0, STREAM_BUFSIZE);
+ aclose(data_socket);
if(infd == -1) {
errstr = vstrallocf(_("error accepting stream: %s"), strerror(errno));
return -1;
tmp_filename = vstralloc(filename, ".tmp", NULL);
pc = strrchr(tmp_filename, '/');
+ g_assert(pc != NULL);
*pc = '\0';
mkholdingdir(tmp_filename);
*pc = '/';
if ((outfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) {
int save_errno = errno;
-
- errstr = squotef(_("holding file \"%s\": %s"),
+ char *m = vstrallocf(_("holding file \"%s\": %s"),
tmp_filename,
strerror(errno));
+
+ errstr = quote_string(m);
+ amfree(m);
amfree(tmp_filename);
aclose(infd);
if(save_errno == ENOSPC) {
int infd,
struct databuf * db)
{
- ssize_t nread;
+ size_t nread;
char header_buf[DISK_BLOCK_BYTES];
startclock();
* need to save into "file", as well as write out. Later, the
* chunk code will rewrite it.
*/
- nread = fullread(infd, header_buf, SIZEOF(header_buf));
- if (nread != DISK_BLOCK_BYTES) {
- if(nread < 0) {
+ nread = full_read(infd, header_buf, SIZEOF(header_buf));
+ if (nread != sizeof(header_buf)) {
+ if(errno != 0) {
errstr = vstrallocf(_("cannot read header: %s"), strerror(errno));
} else {
- errstr = vstrallocf(_("cannot read header: got %zd bytes instead of %d"),
- nread,
- DISK_BLOCK_BYTES);
+ errstr = vstrallocf(_("cannot read header: got %zd bytes instead of %zd"),
+ nread, sizeof(header_buf));
}
return 0;
}
parse_file_header(header_buf, &file, (size_t)nread);
if(write_tapeheader(db->fd, &file)) {
int save_errno = errno;
-
- errstr = squotef(_("write_tapeheader file %s: %s"),
+ char *m = vstrallocf(_("write_tapeheader file %s: %s"),
db->filename, strerror(errno));
+ errstr = quote_string(m);
+ amfree(m);
if(save_errno == ENOSPC) {
putresult(NO_ROOM, "%s %lld\n", handle,
(long long)(db->use+db->split_size-dumpsize));
* We've written the file header. Now, just write data until the
* end.
*/
- while ((nread = fullread(infd, db->buf,
+ while ((nread = full_read(infd, db->buf,
(size_t)(db->datalimit - db->datain))) > 0) {
db->datain += nread;
while(db->dataout < db->datain) {
databuf_flush(
struct databuf * db)
{
- struct cmdargs cmdargs;
+ struct cmdargs *cmdargs = NULL;
int rc = 1;
- ssize_t written;
+ size_t written;
off_t left_in_chunk;
char *arg_filename = NULL;
- char *qarg_filename = NULL;
char *new_filename = NULL;
char *tmp_filename = NULL;
char sequence[NUM_STR_SIZE];
/*
* Probably no more space on this disk. Request some more.
*/
- cmd_t cmd;
-
putresult(RQ_MORE_DISK, "%s\n", handle);
- cmd = getcmd(&cmdargs);
- if(command_in_transit == -1 &&
- (cmd == DONE || cmd == TRYAGAIN || cmd == FAILED)) {
- command_in_transit = cmd;
- cmd = getcmd(&cmdargs);
+ cmdargs = getcmd();
+ if(command_in_transit == NULL &&
+ (cmdargs->cmd == DONE || cmdargs->cmd == TRYAGAIN || cmdargs->cmd == FAILED)) {
+ command_in_transit = cmdargs;
+ cmdargs = getcmd();
}
- if(cmd == CONTINUE) {
+ if(cmdargs->cmd == CONTINUE) {
/*
* CONTINUE
* serial
* chunksize
* use
*/
- cmdargs.argc++; /* true count of args */
- a = 3;
+ a = 2; /* skip CONTINUE and serial */
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker CONTINUE: not enough args: filename]"));
/*NOTREACHED*/
}
- qarg_filename = newstralloc(qarg_filename, cmdargs.argv[a++]);
- if (arg_filename != NULL)
- amfree(arg_filename);
- arg_filename = unquote_string(qarg_filename);
+ arg_filename = newstralloc(arg_filename, cmdargs->argv[a++]);
- if(a >= cmdargs.argc) {
+ 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 = OFF_T_ATOI(cmdargs->argv[a++]);
db->chunk_size = am_floor(db->chunk_size, (off_t)DISK_BLOCK_KB);
- if(a >= cmdargs.argc) {
+ if(a >= cmdargs->argc) {
error(_("error [chunker CONTINUE: not enough args: use]"));
/*NOTREACHED*/
}
- db->use = OFF_T_ATOI(cmdargs.argv[a++]);
+ db->use = OFF_T_ATOI(cmdargs->argv[a++]);
- if(a != cmdargs.argc) {
+ if(a != cmdargs->argc) {
error(_("error [chunker CONTINUE: too many args: %d != %d]"),
- cmdargs.argc, a);
+ cmdargs->argc, a);
/*NOTREACHED*/
}
*/
db->filename = newstralloc(db->filename, arg_filename);
}
- } else if(cmd == ABORT) {
+ } else if(cmdargs->cmd == ABORT) {
abort_pending = 1;
- errstr = newstralloc(errstr, "ERROR");
+ errstr = newstralloc(errstr, cmdargs->argv[1]);
putresult(ABORT_FINISHED, "%s\n", handle);
rc = 0;
goto common_exit;
} else {
- if(cmdargs.argc >= 1) {
- q = squote(cmdargs.argv[1]);
- } else if(cmdargs.argc >= 0) {
- q = squote(cmdargs.argv[0]);
+ if(cmdargs->argc >= 1) {
+ q = quote_string(cmdargs->argv[0]);
} else {
q = stralloc(_("(no input?)"));
}
".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,
db->split_size = dumpsize;
continue;
}
- errstr = squotef(_("creating chunk holding file \"%s\": %s"),
+ 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;
file.cont_filename[0] = '\0';
if(write_tapeheader(newfd, &file)) {
int save_errno = errno;
+ char *m;
aclose(newfd);
if(save_errno == ENOSPC) {
db->split_size = dumpsize;
continue;
}
- errstr = squotef(_("write_tapeheader file %s: %s"),
+ m = vstrallocf(_("write_tapeheader file %s: %s"),
tmp_filename,
strerror(errno));
+ errstr = quote_string(m);
+ amfree(m);
rc = 0;
goto common_exit;
}
* to the next chunk, and then close it.
*/
if (lseek(db->fd, (off_t)0, SEEK_SET) < (off_t)0) {
- errstr = squotef(_("lseek holding file %s: %s"),
+ 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)] = '\0';
+ file.cont_filename[SIZEOF(file.cont_filename)-1] = '\0';
if(write_tapeheader(db->fd, &file)) {
- errstr = squotef(_("write_tapeheader file \"%s\": %s"),
+ 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;
/*
* Write out the buffer
*/
- written = fullwrite(db->fd, db->dataout,
+ written = full_write(db->fd, db->dataout,
(size_t)(db->datain - db->dataout));
if (written > 0) {
db->dataout += written;
dumpsize += (dumpbytes / (off_t)1024);
filesize += (dumpbytes / (off_t)1024);
dumpbytes %= 1024;
- if (written < 0) {
+ if (written == 0) {
if (errno != ENOSPC) {
- errstr = squotef(_("data write: %s"), strerror(errno));
+ char *m = vstrallocf(_("data write: %s"), strerror(errno));
+ errstr = quote_string(m);
+ amfree(m);
rc = 0;
goto common_exit;
}
common_exit:
+ if (cmdargs)
+ free_cmdargs(cmdargs);
amfree(new_filename);
/*@i@*/ amfree(tmp_filename);
amfree(arg_filename);
- amfree(qarg_filename);
return rc;
}
dumpfile_t *file)
{
char *buffer;
- ssize_t written;
+ size_t written;
file->blocksize = DISK_BLOCK_BYTES;
buffer = build_header(file, DISK_BLOCK_BYTES);
- written = fullwrite(outfd, buffer, DISK_BLOCK_BYTES);
+ written = full_write(outfd, buffer, DISK_BLOCK_BYTES);
amfree(buffer);
if(written == DISK_BLOCK_BYTES) return 0;
- if(written < 0) return written;
- errno = ENOSPC;
+
+ /* fake ENOSPC when we get a short write without errno set */
+ if(errno == 0)
+ errno = ENOSPC;
+
return (ssize_t)-1;
}