summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--qacp.c331
-rw-r--r--qarsh.c89
-rw-r--r--qarsh_packet.c13
-rw-r--r--qarsh_packet.h3
-rw-r--r--qarshd.c62
6 files changed, 413 insertions, 87 deletions
diff --git a/Makefile b/Makefile
index ca4f0bd..f7cdb0d 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ TARGETS := qarshd qarsh qacp btimed btimec
all: $(TARGETS)
qarshd: qarshd.c $(COMMON) -lxml2
-qarsh: qarsh.c $(COMMON) -lxml2
+qarsh: qarsh.c $(COMMON) -lxml2 btime.c
qacp: qacp.c $(COMMON) -lxml2
btimed: btimed.c
btimec: btimec.c btime.c
diff --git a/qacp.c b/qacp.c
index aa3f22e..90185dd 100644
--- a/qacp.c
+++ b/qacp.c
@@ -45,29 +45,6 @@ usage()
"qacp [user@]host:<rmtpath> [[user@]host:<rmtpath> ...] <localpath> ");
}
-char *
-copyargs(char **argv)
-{
- int cc;
- char **ap, *p;
- char *args;
-
- cc = 0;
- for (ap = argv; *ap; ++ap)
- cc += strlen(*ap) + 1;
- if (cc == 0) return NULL;
- args = malloc(cc);
- if (!args) {
- perror("qacp: malloc failed in copyargs");
- exit(1);
- }
- for (p = args, ap = argv; *ap; ++ap) {
- for (p = strcpy(p, *ap); *p; ++p);
- if (ap[1])
- *p++ = ' ';
- }
- return args;
-}
void
set_remote_user(char *user, char *group)
@@ -89,6 +66,38 @@ set_remote_user(char *user, char *group)
}
}
+
+struct qp_rstat_pkt *
+qacp_rstat(const char *rmtpath, int *rstaterrno)
+{
+ struct qa_packet *qp;
+ struct qp_rstat_pkt *rstatp;
+
+ qp = make_qp_rstat(rmtpath, NULL);
+ send_packet(qacp_fd, qp);
+ qpfree(qp);
+
+ qp = recv_packet(qacp_fd);
+ if (qp) {
+ if (qp->qp_type == QP_RSTAT) {
+ rstatp = malloc(sizeof *rstatp);
+ rstatp->qp_path = strdup(qp->qp_rstat.qp_path);
+ rstatp->qp_st_mode = qp->qp_rstat.qp_st_mode;
+ rstatp->qp_st_uid = qp->qp_rstat.qp_st_uid;
+ rstatp->qp_st_gid = qp->qp_rstat.qp_st_gid;
+ rstatp->qp_st_size = qp->qp_rstat.qp_st_size;
+ *rstaterrno = 0;
+ } else if (qp->qp_type == QP_RETURNCODE) {
+ rstatp = NULL;
+ *rstaterrno = qp->qp_returncode.qp_errno;
+ }
+
+ qpfree(qp);
+ }
+
+ return rstatp;
+}
+
void
qacp_sendonefile(const char *host, const char *srcfile, const char *destfile)
{
@@ -103,9 +112,6 @@ qacp_sendonefile(const char *host, const char *srcfile, const char *destfile)
off_t offset = 0;
struct stat sb;
- /* Recall that the packet types are qarshd-centric, so if we want
- * to send a file to the host running qarshd we have to tell
- * qarshd to recv a file. */
if ((fd = open(srcfile, O_RDONLY)) <0) {
fprintf(stderr, "Could not open %s: %s\n", srcfile, strerror(errno));
@@ -122,6 +128,10 @@ qacp_sendonefile(const char *host, const char *srcfile, const char *destfile)
sd = bind_any(QARSH_MINPORT);
port = getsockport(sd);
+ /* Recall that the packet types are qarshd-centric, so if we want
+ * to send a file to the host running qarshd we have to tell
+ * qarshd to recv a file. */
+
qp = make_qp_recvfile(destfile, port, sb.st_size, sb.st_mode);
qp->qp_seq = 1;
send_packet(qacp_fd, qp);
@@ -149,65 +159,264 @@ qacp_sendonefile(const char *host, const char *srcfile, const char *destfile)
return;
}
+
void
qacp_recvonefile(const char *host, const char *srcfile, const char *destfile)
{
struct qa_packet *qp;
+ struct sockaddr_in daddr;
+ socklen_t dlen;
+ int sd;
+ int port;
+ int insd;
+ int outfd;
+ char buf[BUFSIZ];
+ ssize_t nread;
+ ssize_t nwrote;
+ ssize_t nleft;
+ struct qp_rstat_pkt *rstatp;
+ int rstaterrno;
+
+ rstatp = qacp_rstat(srcfile, &rstaterrno);
+ if (!rstatp) {
+ fprintf(stderr, "%s: %s\n", srcfile, strerror(rstaterrno));
+ return;
+ }
+
+ if ((outfd = open(destfile, O_TRUNC|O_CREAT|O_WRONLY)) <0) {
+ fprintf(stderr, "Could not open %s: %s\n", destfile, strerror(errno));
+ close(qacp_fd);
+ exit(errno);
+ }
+
+ fchmod(outfd, rstatp->qp_st_mode);
+
+ sd = bind_any(QARSH_MINPORT);
+ port = getsockport(sd);
/* Recall that the packet types are qarshd-centric, so if we want
* to recv a file from the host running qarshd we have to tell
* qarshd to send a file. */
- qp = make_qp_sendfile(srcfile, 88, 8888);
+ qp = make_qp_sendfile(srcfile, port);
qp->qp_seq = 1;
send_packet(qacp_fd, qp);
qpfree(qp);
+ dlen = sizeof daddr;
+ insd = accept(sd, (struct sockaddr *) &daddr, &dlen);
+
+ /* Read/write file */
+ nleft = rstatp->qp_st_size;
+ while (nleft > 0) {
+ nread = read(insd, buf, BUFSIZ);
+ if (nread < 0) {
+ fprintf(stderr, "read() error: %s\n", strerror(errno));
+ break;
+ } else if (nread == 0) { /* EOF */
+ break;
+ }
+
+ nwrote = write(outfd, buf, nread);
+ if (nwrote < 0) {
+ fprintf(stderr, "write() error: %s\n", strerror(errno));
+ break;
+ }
+
+ nleft -= nread;
+ }
+
+ if (nleft != 0) {
+ unlink(destfile);
+ fprintf(stderr, "Short file transfer of %s, "
+ "%zd bytes lost, wanted %ld\n", srcfile, nleft,
+ rstatp->qp_st_size);
+ }
+
+ close(sd);
+ close(insd);
+ close(outfd);
+
+ /* Await our return code from qarshd */
+ qp = recv_packet(qacp_fd);
+ if (qp && qp->qp_type == QP_RETURNCODE
+ && qp->qp_returncode.qp_rc == -1) {
+ fprintf(stderr, "Remote side failed, %s\n",
+ qp->qp_returncode.qp_strerror);
+ close(qacp_fd);
+ exit(125);
+ }
+
return;
}
-struct qp_rstat_pkt *
-qacp_rstat(const char *rmtpath, int *rstaterrno)
+int
+recvfiles(char **argv, int argc, int fileidx, short recursive, short quiet)
{
- struct qa_packet *qp;
+ char *cp;
+ char *rhost = NULL;
+ char *ruser = NULL;
+ char *rgrp = NULL;
+ struct passwd *pw;
+ int file;
+ char *rmtpath;
+ char *destpath;
+ int destisdir;
+ char *tmpstr;
+ char *ldnp; /* local path dirname */
+ char *rbnp; /* remote path basename */
struct qp_rstat_pkt *rstatp;
+ struct stat sb;
+ int rstaterrno;
- qp = make_qp_rstat(rmtpath, NULL);
- send_packet(qacp_fd, qp);
- qpfree(qp);
+ if (strchr(argv[argc-1], ':') != NULL) {
+ fprintf(stderr, "%s is not a valid local file string\n",
+ argv[argc-1]);
+ return -1;
+ }
- qp = recv_packet(qacp_fd);
- if (qp) {
- if (qp->qp_type == QP_RSTAT) {
- rstatp = malloc(sizeof *rstatp);
- rstatp->qp_path = strdup(qp->qp_rstat.qp_path);
- rstatp->qp_st_mode = qp->qp_rstat.qp_st_mode;
- rstatp->qp_st_uid = qp->qp_rstat.qp_st_uid;
- rstatp->qp_st_gid = qp->qp_rstat.qp_st_gid;
- rstatp->qp_st_size = qp->qp_rstat.qp_st_size;
- *rstaterrno = 0;
- } else if (qp->qp_type == QP_RETURNCODE) {
- rstatp = NULL;
- *rstaterrno = qp->qp_returncode.qp_errno;
+ destpath = strdup(argv[argc-1]);
+
+ /* Figure out if our destpath is just a dir.
+ * If so we need to set the flag to tack on the remote
+ * path basename onto our destpath
+ */
+
+ if (stat(destpath, &sb) < 0) {
+ /* stat couldn't file the file, check if the dirname exists,
+ * if so we need to reset our destpath to the local dirname
+ * if that directory exists.
+ */
+ tmpstr = strdup(destpath);
+ ldnp = strdup(dirname(tmpstr));
+ free(tmpstr);
+ if (stat(ldnp, &sb) < 0) {
+ fprintf(stderr, "%s: %s\n", ldnp, strerror(errno));
+ return -1;
}
- qpfree(qp);
- }
+ if (S_ISDIR(sb.st_mode)) {
+ /* No, we don't want to set destisdir, as our dest is really
+ * a full path, we striped off the filename above to check
+ * the rest of the path exists.
+ */
+ destisdir = 0;
+ } else {
+ fprintf(stderr, "%s not a directory\n", ldnp);
+ return -1;
+ }
+ } else {
+ if (S_ISDIR(sb.st_mode)) {
+ destisdir = 1;
+ } else if (S_ISREG(sb.st_mode)) {
+ destisdir = 0;
+ } else {
+ fprintf(stderr, "%s not a file or directory\n", destpath);
+ return -1;
+ }
+ }
+
- return rstatp;
-}
+ for (file = fileidx; file < (argc - 1); file++) {
+
+ /* For each file in remote file list (fileidx to argc-2) */
+ /* Rstat the file, if it is a dir, error */
+ /* Otherwise copy it to local location */
+
+ if (strchr(argv[file], ':') == NULL) {
+ fprintf(stderr, "%s is not a valid remote host:file string\n",
+ argv[file]);
+ return -1;
+ }
+
+ rhost = strdup(argv[file]);
+ cp = strchr(rhost, ':');
+ *cp = '\0';
+
+ /* Grab any user/group info */
+ if ((cp = strchr(rhost, '@'))) {
+ ruser = rhost;
+ rhost = cp+1;
+ *cp = '\0';
+ }
+
+ if (ruser && (cp = strchr(ruser, '.'))) {
+ rgrp = cp+1;
+ *cp = '\0';
+ }
+
+ if (!(pw = getpwuid(getuid()))) {
+ fprintf(stderr, "qacp: unknown user id.\n");
+ return -1;
+ }
+
+ if (ruser == NULL) {
+ ruser = strdup(pw->pw_name);
+ }
+
+ qacp_fd = connect_to_host(rhost, QARSHD_CONTROL_PORT);
+ if (qacp_fd == -1) {
+ if (errno == 0) {
+ fprintf(stderr, "Could not connect to %s:%d, %d: %s\n",
+ rhost, QARSHD_CONTROL_PORT, h_errno, hstrerror(h_errno));
+ } else {
+ fprintf(stderr, "Could not connect to %s:%d, %d: %s\n",
+ rhost, QARSHD_CONTROL_PORT, errno, strerror(errno));
+ }
+ return -1;
+ }
+
+ set_remote_user(ruser, rgrp);
+
+ cp = strdup(argv[file]);
+ cp = strchr(argv[file], ':');
+ cp++;
+
+ rmtpath = strdup(cp);
+
+ rstatp = qacp_rstat(rmtpath, &rstaterrno);
+ if (rstatp) {
+ if (S_ISREG(rstatp->qp_st_mode)) {
+ if (destisdir) {
+ cp = strdup(rmtpath);
+ rbnp = strdup(basename(cp));
+ free(cp);
+
+ cp = malloc(strlen(destpath) + strlen(rbnp) + 2);
+ strcpy(cp, destpath);
+ strcat(cp, "/");
+ strcat(cp, rbnp);
+
+ qacp_recvonefile(rhost, rmtpath, cp);
+ free(cp);
+ free(rbnp);
+ } else {
+ if (!quiet) {
+ printf("%s:%s -> %30.30s\n",
+ rhost, rmtpath, destpath);
+ }
+ qacp_recvonefile(rhost, rmtpath, destpath);
+ }
+ }
+ if (S_ISDIR(rstatp->qp_st_mode)) {
+ fprintf(stderr, "%s: Not a regular file\n", argv[file]);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "%s: %s\n", argv[file], strerror(rstaterrno));
+ return -1;
+ }
+
+ close(qacp_fd);
+ }
-int
-recvfiles(char **argv, int argc, short recursive, short quiet)
-{
- puts("recvfiles() NA");
return 0;
}
int
-sendfiles(char **argv, int argc, short recursive, short quiet)
+sendfiles(char **argv, int argc, int fileidx, short recursive, short quiet)
{
char *cp;
char *rhost = NULL;
@@ -276,7 +485,7 @@ sendfiles(char **argv, int argc, short recursive, short quiet)
rstatp = qacp_rstat(rmtpath, &rstaterrno);
- for (file = optind; file < (argc - 1); file++) {
+ for (file = fileidx; file < (argc - 1); file++) {
tmpstr = strdup(argv[file]);
lbnp = strdup(basename(tmpstr));
free(tmpstr);
@@ -318,7 +527,7 @@ sendfiles(char **argv, int argc, short recursive, short quiet)
}
if (!quiet) {
- printf("%-40.40s -> %s:%s\n", argv[file], rhost, destpath);
+ printf("%-30.30s -> %s:%s\n", argv[file], rhost, destpath);
}
qacp_sendonefile(rhost, argv[file], destpath);
@@ -342,6 +551,8 @@ main(int argc, char *argv[])
while ((c = getopt(argc, argv, "+rq")) != -1) {
switch (c) {
case 'r':
+ fprintf(stderr, "-r not supported\n");
+ exit(2);
recursive = 1;
break;
case 'q':
@@ -355,7 +566,7 @@ main(int argc, char *argv[])
}
}
- if (argv[optind + 1] == NULL) {
+ if (argv[optind] == NULL) {
usage();
exit(2);
}
@@ -363,11 +574,11 @@ main(int argc, char *argv[])
eflag = 0;
/* If last arg has a ':' then we are sending files */
if (strchr(argv[argc-1], ':') != NULL) {
- if (sendfiles(argv, argc, recursive, quiet) < 0) {
+ if (sendfiles(argv, argc, optind, recursive, quiet) < 0) {
eflag++;
}
} else {
- if (recvfiles(argv, argc, recursive, quiet) < 0) {
+ if (recvfiles(argv, argc, optind, recursive, quiet) < 0) {
eflag++;
}
}
diff --git a/qarsh.c b/qarsh.c
index b0c4aab..5521311 100644
--- a/qarsh.c
+++ b/qarsh.c
@@ -21,22 +21,34 @@
#include <syslog.h>
#include <pwd.h>
-
#include "sockutil.h"
#include "qarsh_packet.h"
+#include "btime.h"
#define QARSH_MINPORT 5010
/* Globals */
int qarsh_fd = -1; /* The control connection to qarshd */
+char *qarshd_host; /* hostname of remote host */
+int qarsh_allowed_hbeatmisses = 100;
int signal_to_send = 0;
int sigs_to_propogate[] = { SIGINT, SIGTERM, SIGHUP, SIGUSR1, SIGUSR2 };
sigset_t pselect_sigmask;
void
-usage()
+usage(const char *pname)
{
- printf("qarsh: [user[.group]@]hostname cmdline ...\n");
+ fprintf(stderr, "%s [options] [user[.group]@]hostname cmdline ...\n"
+ "-l user Run cmdline using this user name.\n"
+ "-g group Run cmdline using this group name.\n"
+ "-p port Use this port to contact qarshd.\n"
+ "-m misscount Number of missed heartbeats allowed.\n"
+ " A value of 0 disables heartbeats.\n"
+ " Default is value is <%d>.\n"
+
+ ,pname, qarsh_allowed_hbeatmisses);
+
+ return;
}
char *
@@ -110,6 +122,29 @@ set_remote_user(char *user, char *group)
}
}
+unsigned int
+heartbeat(const char *host)
+{
+ int retry;
+ unsigned int hbeat;
+
+ /* User disabled heart beating */
+ if (qarsh_allowed_hbeatmisses == 0) {
+ return 1;
+ }
+
+ for (retry = 0; retry < qarsh_allowed_hbeatmisses; retry++) {
+ if ((hbeat = btime(host)) == 0) {
+ fprintf(stderr, "qarsh: INFO -- missed heartbeat %d\n", retry);
+ sleep(retry);
+ } else {
+ break;
+ }
+ }
+
+ return hbeat;
+}
+
int
run_remote_cmd(char *cmdline)
{
@@ -124,6 +159,16 @@ run_remote_cmd(char *cmdline)
int nset;
struct sockaddr_in caddr;
socklen_t clen;
+ struct timespec timeout;
+ unsigned int start_hbeat;
+ unsigned int hbeat;
+
+ /* Use remote node boot time as hearbeat */
+ start_hbeat = heartbeat(qarshd_host);
+ if (!start_hbeat) {
+ fprintf(stderr, "Can not initialize heartbeat from %s\n", qarshd_host);
+ return 1;
+ }
l_in = bind_any(QARSH_MINPORT);
p_in = getsockport(l_in);
@@ -203,11 +248,28 @@ run_remote_cmd(char *cmdline)
memset(buf, 0, 1024);
for (;;) {
+ timeout.tv_sec = 5;
+ timeout.tv_nsec = 0;
testfds = readfds;
memset(buf, 0, 1024);
- nset = pselect(FD_SETSIZE, &testfds, NULL, NULL, NULL,
+ nset = pselect(FD_SETSIZE, &testfds, NULL, NULL, &timeout,
&pselect_sigmask);
+
+ if (nset == 0) {
+ hbeat = heartbeat(qarshd_host);
+ if ((!hbeat) ||
+ (abs(hbeat - start_hbeat)) > 5) {
+ fprintf(stderr, "No heartbeat from %s\n", qarshd_host);
+ /* Set our return packet as NULL so we exit
+ * with unknown error. */
+ qp = NULL;
+ break;
+ }
+
+ continue;
+ }
+
if (nset == -1 && errno == EINTR) {
/* Only test signals */
if (signal_to_send) {
@@ -253,6 +315,10 @@ run_remote_cmd(char *cmdline)
}
if (nset && FD_ISSET(qarsh_fd, &testfds)) {
qp = recv_packet(qarsh_fd);
+ if (qp == NULL) {
+ fprintf(stderr, "recv_packet() returned NULL!\n:");
+ break;
+ }
/* dump_qp(qp); */
if (qp && qp->qp_type == QP_CMDEXIT) {
@@ -294,7 +360,7 @@ main(int argc, char *argv[])
openlog("qarsh", LOG_PID, LOG_DAEMON);
- while ((c = getopt(argc, argv, "+p:l:g:")) != -1) {
+ while ((c = getopt(argc, argv, "+p:l:g:m:")) != -1) {
switch (c) {
case 'l':
remuser = strdup(optarg);
@@ -305,17 +371,21 @@ main(int argc, char *argv[])
case 'p':
port = atoi(optarg);
break;
+ case 'm':
+ qarsh_allowed_hbeatmisses = atoi(optarg);
+ break;
case '?':
default:
printf("Unknown option %c\n", (char)optopt);
- usage();
+ usage(argv[0]);
exit(1);
} }
if ((host = argv[optind++]) == NULL) {
- usage();
+ usage(argv[0]);
exit(1);
}
+
/* check for user and group in form [user[.group]@]hostname */
{
char *sp;
@@ -341,9 +411,11 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
if ((args = copyargs(argv)) == NULL) {
- usage();
+ usage(argv[0]);
exit(1);
}
+
+ qarshd_host = strdup(host);
qarsh_fd = connect_to_host(host, port);
if (qarsh_fd == -1) {
if (errno == 0) {
@@ -361,5 +433,6 @@ main(int argc, char *argv[])
ret = run_remote_cmd(args);
close(qarsh_fd);
free(args);
+ free(qarshd_host);
return ret;
}
diff --git a/qarsh_packet.c b/qarsh_packet.c
index 76fadf1..151beff 100644
--- a/qarsh_packet.c
+++ b/qarsh_packet.c
@@ -277,9 +277,6 @@ parse_qp_sendfile(xmlXPathContextPtr ctxt, struct qa_packet *qp)
s = get_xpath_string(ctxt, "param[@name='of_port']");
qp->qp_sendfile.qp_of_port = atoi(s);
free(s);
- s = get_xpath_string(ctxt, "param[@name='count']");
- qp->qp_sendfile.qp_count = atoi(s);
- free(s);
return 0;
}
@@ -480,7 +477,7 @@ void string_qp_recvfile(xmlNodePtr node, struct qa_packet *qp)
snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_if_port);
xmlAddChild(node, make_param("if_port", tmpstr));
- snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_count);
+ snprintf(tmpstr, 32, "%zd", qp->qp_recvfile.qp_count);
xmlAddChild(node, make_param("count", tmpstr));
snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_mode);
@@ -494,8 +491,6 @@ void string_qp_sendfile(xmlNodePtr node, struct qa_packet *qp)
xmlAddChild(node, make_param("path", qp->qp_sendfile.qp_path));
snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_of_port);
xmlAddChild(node, make_param("of_port", tmpstr));
- snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_count);
- xmlAddChild(node, make_param("count", tmpstr));
}
void string_qp_rstat(xmlNodePtr node, struct qa_packet *qp)
@@ -672,7 +667,7 @@ make_qp_recvfile(const char *path, int if_port, size_t count, mode_t mode)
}
struct qa_packet *
-make_qp_sendfile(const char *path, int of_port, size_t count)
+make_qp_sendfile(const char *path, int of_port)
{
struct qa_packet *qp;
qp = malloc(sizeof *qp);
@@ -682,7 +677,6 @@ make_qp_sendfile(const char *path, int of_port, size_t count)
qp->qp_type = QP_SENDFILE;
qp->qp_sendfile.qp_path = strdup(path);
qp->qp_sendfile.qp_of_port = of_port;
- qp->qp_sendfile.qp_count = count;
return qp;
}
@@ -818,7 +812,7 @@ dump_qp_recvfile(struct qa_packet *qp)
{
printf("\tpath: %s\n", qp->qp_recvfile.qp_path);
printf("\tif_port: %d\n", qp->qp_recvfile.qp_if_port);
- printf("\tcount: %d\n", qp->qp_recvfile.qp_count);
+ printf("\tcount: %zd\n", qp->qp_recvfile.qp_count);
printf("\tmode: %o\n", qp->qp_recvfile.qp_mode);
}
@@ -827,7 +821,6 @@ dump_qp_sendfile(struct qa_packet *qp)
{
printf("\tpath: %s\n", qp->qp_sendfile.qp_path);
printf("\tof_port: %d\n", qp->qp_sendfile.qp_of_port);
- printf("\tcount: %d\n", qp->qp_sendfile.qp_count);
}
void
diff --git a/qarsh_packet.h b/qarsh_packet.h
index c4316fd..07e90e7 100644
--- a/qarsh_packet.h
+++ b/qarsh_packet.h
@@ -67,7 +67,6 @@ struct qp_recvfile_pkt {
struct qp_sendfile_pkt {
char *qp_path;
int qp_of_port;
- size_t qp_count;
};
struct qp_rstat_pkt {
@@ -120,7 +119,7 @@ struct qa_packet *make_qp_cmdexit(pid_t pid, int status);
struct qa_packet *make_qp_setuser(char *user, char *group);
struct qa_packet *make_qp_kill(int sig);
struct qa_packet *make_qp_recvfile(const char *path, int if_port, size_t count, mode_t mode);
-struct qa_packet *make_qp_sendfile(const char *path, int of_port, size_t count);
+struct qa_packet *make_qp_sendfile(const char *path, int of_port);
struct qa_packet *make_qp_rstat(const char *path, const struct stat *sb);
char *qptostr(struct qa_packet *qp, char **qpstr, int *qpsize);
void qpfree(struct qa_packet *qp);
diff --git a/qarshd.c b/qarshd.c
index ee9e556..4392db8 100644
--- a/qarshd.c
+++ b/qarshd.c
@@ -13,6 +13,7 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
+#include <sys/sendfile.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <grp.h>
@@ -137,7 +138,7 @@ recvfile(const char *path, int if_port, size_t count, mode_t mode)
if (nleft != 0) {
unlink(path);
syslog(LOG_WARNING, "Short file transfer in recvfile(), "
- "%d bytes lost, wanted %d\n", nleft, count);
+ "%zd bytes lost, wanted %zd\n", nleft, count);
}
close(sd);
@@ -146,6 +147,46 @@ recvfile(const char *path, int if_port, size_t count, mode_t mode)
return count - nleft;
}
+ssize_t
+pushfile(const char *path, int of_port)
+{
+ int outsd;
+ int infd;
+ off_t offset = 0;
+ ssize_t nbytes;
+ struct stat sb;
+
+ outsd = connect_to_peer(&peername, of_port);
+ if (outsd == -1) {
+ syslog(LOG_WARNING, "Connect to of_port (%d) failed: %s\n",
+ of_port, strerror(errno));
+ return -1;
+ }
+
+ infd = open(path, O_RDONLY);
+ if (infd == -1) {
+ syslog(LOG_WARNING, "Could not open %s: %s\n",
+ path, strerror(errno));
+ close(outsd);
+ return -1;
+ }
+
+ if (fstat(infd, &sb) < 0) {
+ syslog(LOG_WARNING, "Could not stat %s: %s\n",
+ path, strerror(errno));
+ close(infd);
+ close(outsd);
+ return -1;
+ }
+
+ nbytes = sendfile(outsd, infd, &offset, sb.st_size);
+
+ close(infd);
+ close(outsd);
+
+ return nbytes;
+}
+
struct qa_packet *
rstat(const char *path)
{
@@ -186,6 +227,7 @@ handle_packets(int infd)
for (;;) {
FD_SET(infd, &rfds);
timeout.tv_sec = 3;
+ timeout.tv_nsec = 0;
nfd = pselect(infd+1, &rfds, NULL, NULL, &timeout, &orig_sigmask);
@@ -238,7 +280,7 @@ handle_packets(int infd)
break;
case QP_RECVFILE:
syslog(LOG_INFO, "Got a QP_RECVFILE with path = %s, "
- "ifd = %d, count = %d, mode = %o\n",
+ "ifd = %d, count = %zd, mode = %o\n",
qp->qp_recvfile.qp_path,
qp->qp_recvfile.qp_if_port,
qp->qp_recvfile.qp_count,
@@ -251,7 +293,7 @@ handle_packets(int infd)
rp = make_qp_returncode(-1, errno, strerror(errno));
} else if (nbytes < qp->qp_recvfile.qp_count) {
char tmpstr[512];
- sprintf(tmpstr, "Excpected %d, wrote %d\n",
+ sprintf(tmpstr, "Excpected %zd, wrote %zd\n",
qp->qp_recvfile.qp_count, nbytes);
rp = make_qp_returncode(-1, 0, tmpstr);
} else {
@@ -262,10 +304,18 @@ handle_packets(int infd)
break;
case QP_SENDFILE:
syslog(LOG_INFO, "Got a QP_SENDFILE with path = %s, "
- "ofd = %d, count = %d\n",
+ "ofd = %d\n",
qp->qp_sendfile.qp_path,
- qp->qp_sendfile.qp_of_port,
- qp->qp_sendfile.qp_count);
+ qp->qp_sendfile.qp_of_port);
+ nbytes = pushfile(qp->qp_sendfile.qp_path,
+ qp->qp_sendfile.qp_of_port);
+ if (nbytes < 0) {
+ rp = make_qp_returncode(-1, errno, strerror(errno));
+ } else {
+ rp = make_qp_returncode(0, 0, "Transfer Complete");
+ }
+ send_packet(fileno(stdout), rp);
+ qpfree(rp);
break;
case QP_RSTAT:
syslog(LOG_INFO, "Got a QP_RSTAT with path = %s\n",