summaryrefslogtreecommitdiffstats
path: root/qarsh/qacp.c
diff options
context:
space:
mode:
Diffstat (limited to 'qarsh/qacp.c')
-rw-r--r--qarsh/qacp.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/qarsh/qacp.c b/qarsh/qacp.c
new file mode 100644
index 0000000..b404482
--- /dev/null
+++ b/qarsh/qacp.c
@@ -0,0 +1,334 @@
+/*
+ * QA Remote Copy - client side
+ *
+ * Copy a file to, or from, server.
+ *
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sys/sendfile.h>
+#include <libgen.h>
+
+
+#include "sockutil.h"
+#include "qarsh_packet.h"
+
+#define QARSHD_CONTROL_PORT 5008
+#define QARSH_MINPORT 5010
+
+/* Globals */
+int qacp_fd = -1; /* The control connection to qacpd */
+
+void
+usage()
+{
+/* printf("usage: qacp: [-r] [[user@]host1:]file1 [...] " */
+ /* "[[user@]host2:]file2\n"); */
+
+ /* For now, only simple cmdlines */
+ fprintf(stderr, "usage:\n\t%s\n\t%s\n",
+ "qacp <localpath> [<loacalpath> ...] [user@]host:<rmtpath>",
+ "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)
+{
+ struct qa_packet *qp;
+
+ qp = make_qp_setuser(user, group);
+ qp->qp_seq = 1;
+ send_packet(qacp_fd, qp);
+ qpfree(qp);
+ 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);
+ }
+}
+
+void
+qacp_sendonefile(const char *host, const char *srcfile, const char *destfile)
+{
+ struct qa_packet *qp;
+ struct sockaddr_in daddr;
+ socklen_t dlen;
+ int fd;
+ int sd;
+ int outsd;
+ int port;
+ ssize_t nbytes;
+ 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));
+ close(qacp_fd);
+ exit(errno);
+ }
+
+ if (fstat(fd, &sb) < 0) {
+ fprintf(stderr, "Could not stat %s: %s\n", srcfile, strerror(errno));
+ close(qacp_fd);
+ exit(errno);
+ }
+
+ sd = bind_any(QARSH_MINPORT);
+ port = getsockport(sd);
+
+ qp = make_qp_recvfile(destfile, port, sb.st_size, sb.st_mode);
+ qp->qp_seq = 1;
+ send_packet(qacp_fd, qp);
+ qpfree(qp);
+
+ dlen = sizeof daddr;
+ outsd = accept(sd, (struct sockaddr *) &daddr, &dlen);
+
+ nbytes = sendfile(outsd, fd, &offset, sb.st_size);
+
+ close(sd);
+ close(outsd);
+ close(fd);
+
+ /* 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;
+}
+
+void
+qacp_recvonefile(const char *host, const char *srcfile, const char *destfile)
+{
+ struct qa_packet *qp;
+
+ /* 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->qp_seq = 1;
+ send_packet(qacp_fd, qp);
+ qpfree(qp);
+
+ return;
+}
+
+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)
+{
+ char *cp;
+ char *rhost = NULL;
+ char *ruser = NULL;
+ char *rgrp = NULL;
+ struct passwd *pw;
+ int file;
+ char *rmtpath;
+ char *destpath;
+ char *tmpstr;
+ char *lbnp; /* local file basename */
+ char *ldnp; /* local file dirname */
+ char *rbnp; /* remote file basename */
+ char *rdnp; /* remote file dirname */
+
+ if (strchr(argv[argc-1], ':') == NULL) {
+ fprintf(stderr, "%s is not a valid remote host:file string\n",
+ argv[argc-1]);
+ return -1;
+ }
+
+ rhost = strdup(argv[argc-1]);
+ 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[argc-1]);
+ cp = strchr(argv[argc-1], ':');
+ cp++;
+ rmtpath = strdup(cp);
+
+ tmpstr = strdup(rmtpath);
+ rdnp = strdup(dirname(tmpstr));
+ free(tmpstr);
+
+ tmpstr = strdup(rmtpath);
+ rbnp = strdup(basename(tmpstr));
+ free(tmpstr);
+
+
+ for (file = optind; file < (argc - 1); file++) {
+ tmpstr = strdup(argv[file]);
+ lbnp = strdup(basename(tmpstr));
+ free(tmpstr);
+
+ tmpstr = strdup(argv[file]);
+ ldnp = strdup(dirname(tmpstr));
+ free(tmpstr);
+
+ if (strcmp(lbnp, rbnp)) {
+ /* Tack on our lbnp to rmtpath */
+ destpath = malloc(strlen(rmtpath) + strlen(lbnp) + 2);
+ memset(destpath, 0, strlen(destpath));
+ strcpy(destpath, rmtpath);
+ strcat(destpath, "/");
+ strcat(destpath, lbnp);
+ } else {
+ destpath = strdup(rmtpath);
+ }
+
+ if (!quiet) {
+ printf("%-20.20s -> %s:%s\n", file[argv], rhost, destpath);
+ }
+
+ qacp_sendonefile(rhost, file[argv], destpath);
+
+ free(destpath);
+ }
+
+ return 0;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ short recursive=0;
+ short quiet=0;
+ int eflag;
+
+ while ((c = getopt(argc, argv, "+rq")) != -1) {
+ switch (c) {
+ case 'r':
+ recursive = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case '?':
+ default:
+ printf("Unknown option %c\n", (char)optopt);
+ usage();
+ exit(1);
+ }
+ }
+
+ if (argv[optind + 1] == NULL) {
+ usage();
+ exit(2);
+ }
+
+ 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) {
+ eflag++;
+ }
+ } else {
+ if (recvfiles(argv, argc, recursive, quiet) < 0) {
+ eflag++;
+ }
+ }
+
+ close(qacp_fd);
+
+ if (eflag) {
+ exit(1);
+ }
+
+ exit(0);
+}