summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1997-06-04 18:22:14 +0000
committerMiles Bader <miles@gnu.org>1997-06-04 18:22:14 +0000
commit9caab9ea07e76d3169cdc61cc7b53834c2e4eeba (patch)
tree111b41f4f22f3d23f65ef3e71273ccd85311e259
parent178b779a967a2ffd93fa649ee0cbaba5b1391be4 (diff)
Moved here from ../libftpconn
-rw-r--r--utils/ftpcp.c336
-rw-r--r--utils/ftpdir.c328
2 files changed, 664 insertions, 0 deletions
diff --git a/utils/ftpcp.c b/utils/ftpcp.c
new file mode 100644
index 00000000..92bcabf2
--- /dev/null
+++ b/utils/ftpcp.c
@@ -0,0 +1,336 @@
+/* Copy a file using the ftp protocol
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <error.h>
+#include <argp.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#include <version.h>
+
+#include <ftpconn.h>
+
+#define COPY_SZ 65536
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ftpcp);
+
+#define OPT_SRC_U -3
+#define OPT_SRC_A -4
+#define OPT_SRC_P -5
+#define OPT_DST_U -6
+#define OPT_DST_A -7
+#define OPT_DST_P -8
+
+
+static struct argp_option options[] =
+{
+ {"user", 'u', "USER",0, "User to login as on both ftp servers"},
+ {"password", 'p', "PWD", 0, "USER's password"},
+ {"account", 'a', "ACCT",0, "Account to login as"},
+ {"src-user", OPT_SRC_U, "USER",0, "User to login as on the src ftp server"},
+ {"src-password",OPT_SRC_P, "PWD", 0, "The src USER's password"},
+ {"src-account", OPT_SRC_A, "ACCT",0, "Account to login as on the source server"},
+ {"dst-user", OPT_DST_U, "USER",0, "User to login as on the dst ftp server"},
+ {"dst-password",OPT_DST_P, "PWD", 0, "The dst USER's password"},
+ {"dst-account", OPT_DST_A, "ACCT",0, "Account to login as on the source server"},
+ {"debug", 'D', 0, 0, "Turn on debugging output for ftp connections"},
+ {0, 0}
+};
+static char *args_doc = "SRC [DST]";
+static char *doc = "Copy file SRC over ftp to DST."
+"\vBoth SRC and DST may have the form HOST:FILE, FILE, or -, where - is"
+" standard input for SRC or standard output for DST, and FILE is a local"
+" file. DST may be a directory, in which case the basename of SRC is"
+" appended to make the actual destination filename.";
+
+/* customization hooks. */
+static struct ftp_conn_hooks conn_hooks = { 0 };
+
+static void
+cntl_debug (struct ftp_conn *conn, int type, const char *txt)
+{
+ char *type_str;
+
+ switch (type)
+ {
+ case FTP_CONN_CNTL_DEBUG_CMD: type_str = "."; break;
+ case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
+ default: type_str = "?"; break;
+ }
+
+ fprintf (stderr, "%s%s\n", type_str, txt);
+}
+
+/* Return an ftp connection for the host NAME using PARAMS. If an error
+ occurrs, a message is printed the program exits. If CNAME is non-zero,
+ the host's canonical name, in mallocated storage, is returned in it. */
+struct ftp_conn *
+get_host_conn (char *name, struct ftp_conn_params *params, char **cname)
+{
+ error_t err;
+ struct hostent *he;
+ struct ftp_conn *conn;
+
+ he = gethostbyname (name);
+ if (! he)
+ error (10, 0, "%s: %s", name, hstrerror (h_errno));
+
+ params->addr = malloc (he->h_length);
+ if (! params->addr)
+ error (11, ENOMEM, "%s", name);
+
+ bcopy (he->h_addr_list[0], params->addr, he->h_length);
+ params->addr_len = he->h_length;
+ params->addr_type = he->h_addrtype;
+
+ err = ftp_conn_create (params, &conn_hooks, &conn);
+ if (err)
+ error (12, err, "%s", he->h_name);
+
+ if (cname)
+ *cname = strdup (he->h_name);
+
+ return conn;
+}
+
+static void
+cp (int src, const char *src_name, int dst, const char *dst_name)
+{
+ ssize_t rd;
+ static void *copy_buf = 0;
+
+ if (! copy_buf)
+ {
+ copy_buf = valloc (COPY_SZ);
+ if (! copy_buf)
+ error (13, ENOMEM, "Cannot allocate copy buffer");
+ }
+
+ while ((rd = read (src, copy_buf, COPY_SZ)) > 0)
+ do
+ {
+ int wr = write (dst, copy_buf, rd);
+ if (wr < 0)
+ error (14, errno, "%s", dst_name);
+ rd -= wr;
+ }
+ while (rd > 0);
+
+ if (rd != 0)
+ error (15, errno, "%s", src_name);
+}
+
+struct epoint
+{
+ char *name; /* Name, of the form HOST:FILE, FILE, or -. */
+ char *file; /* If remote, the FILE portion, or 0. */
+ int fd; /* A file descriptor to use. */
+ struct ftp_conn *conn; /* An ftp connection to use. */
+ struct ftp_conn_params params;
+};
+
+static void
+econnect (struct epoint *e, struct ftp_conn_params *def_params)
+{
+ char *rmt;
+
+ if (! e->name)
+ e->name = "-";
+
+ rmt = strchr (e->name, ':');
+ if (rmt)
+ {
+ error_t err;
+
+ *rmt++ = 0;
+
+ if (! e->params.user)
+ e->params.user = def_params->user;
+ if (! e->params.pass)
+ e->params.pass = def_params->pass;
+ if (! e->params.acct)
+ e->params.acct = def_params->acct;
+
+ e->conn = get_host_conn (e->name, &e->params, &e->name);
+ e->name = realloc (e->name, strlen (e->name) + 1 + strlen (rmt) + 1);
+ if (! e->name)
+ error (22, ENOMEM, "Cannot allocate name storage");
+
+ err = ftp_conn_set_type (e->conn, "I");
+ if (err)
+ error (23, err, "%s: Cannot set connection type to binary",
+ e->name);
+
+ strcat (e->name, ":");
+ strcat (e->name, rmt);
+
+ e->file = rmt;
+ }
+ else if (e->params.user || e->params.pass || e->params.acct)
+ error (20, 0,
+ "%s: Ftp login parameter specified for a local endpoint (%s,%s,%s)",
+ e->name, e->params.user, e->params.pass, e->params.acct);
+ else
+ e->file = strdup (e->name);
+}
+
+static error_t
+eopen_wr (struct epoint *e, int *fd)
+{
+ if (e->conn)
+ return ftp_conn_start_store (e->conn, e->file, fd);
+ else if (strcmp (e->name, "-") == 0)
+ *fd = 1;
+ else
+ {
+ *fd = open (e->name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (*fd < 0)
+ return errno;
+ }
+ return 0;
+}
+
+static error_t
+eopen_rd (struct epoint *e, int *fd)
+{
+ if (e->conn)
+ return ftp_conn_start_retrieve (e->conn, e->file, fd);
+ else if (strcmp (e->name, "-") == 0)
+ *fd = 0;
+ else
+ {
+ *fd = open (e->name, O_RDONLY, 0666);
+ if (*fd < 0)
+ return errno;
+ }
+ return 0;
+}
+
+static void
+efinish (struct epoint *e)
+{
+ if (e->conn)
+ {
+ error_t err = ftp_conn_finish_transfer (e->conn);
+ if (err)
+ error (31, err, "%s", e->name);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct epoint rd = { 0 }, wr = { 0 };
+ struct ftp_conn_params def_params = { 0 }; /* default params */
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ switch (state->arg_num)
+ {
+ case 0: rd.name = arg; break;
+ case 1: wr.name = arg; break;
+ default: return ARGP_ERR_UNKNOWN;
+ }
+ break;
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+
+ case 'u': def_params.user = arg; break;
+ case 'p': def_params.pass = arg; break;
+ case 'a': def_params.acct = arg; break;
+
+ case OPT_SRC_U: rd.params.user = arg; break;
+ case OPT_SRC_P: rd.params.pass = arg; break;
+ case OPT_SRC_A: rd.params.acct = arg; break;
+
+ case OPT_DST_U: wr.params.user = arg; break;
+ case OPT_DST_P: wr.params.pass = arg; break;
+ case OPT_DST_A: wr.params.acct = arg; break;
+
+ case 'D': conn_hooks.cntl_debug = cntl_debug; break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ econnect (&rd, &def_params);
+ econnect (&wr, &def_params);
+
+ if (rd.conn && wr.conn)
+ {
+ err = ftp_conn_rmt_copy (rd.conn, rd.file, wr.conn, wr.file);
+ if (err)
+ error (30, err, "Remote copy");
+ }
+ else
+ {
+ int rd_fd, wr_fd;
+
+ err = eopen_rd (&rd, &rd_fd);
+ if (err)
+ error (31, err, "%s", rd.name);
+
+ err = eopen_wr (&wr, &wr_fd);
+ if (err == EISDIR)
+ /* The destination name is a directory; try again with the source
+ basename appended. */
+ {
+ char *bname = basename (rd.file);
+ size_t bname_len = strlen (bname);
+ char *dir = wr.file;
+ char *name = malloc (strlen (dir) + 1 + bname_len + 1);
+
+ if (! name)
+ error (99, ENOMEM, "%s", dir);
+
+ strcpy (name, dir);
+ strcat (name, "/");
+ strcat (name, bname);
+ wr.file = name;
+
+ err = eopen_wr (&wr, &wr_fd);
+ }
+ if (err)
+ error (32, err, "%s", wr.name);
+
+ cp (rd_fd, rd.name, wr_fd, wr.name);
+
+ close (rd_fd);
+ close (wr_fd);
+
+ efinish (&rd);
+ efinish (&wr);
+ }
+
+ exit (0);
+}
diff --git a/utils/ftpdir.c b/utils/ftpdir.c
new file mode 100644
index 00000000..b7bcce2b
--- /dev/null
+++ b/utils/ftpdir.c
@@ -0,0 +1,328 @@
+/* Get a directory listing using the ftp protocol
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <string.h>
+#include <error.h>
+#include <argp.h>
+#include <time.h>
+#include <netdb.h>
+
+#include <version.h>
+
+#include <ftpconn.h>
+
+#define COPY_SZ 65536
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ftpdir);
+
+static struct argp_option options[] =
+{
+ {"user", 'u', "USER",0, "User to login as on ftp server"},
+ {"password", 'p', "PWD", 0, "USER's password"},
+ {"account", 'a', "ACCT",0, "Account to login as"},
+ {"separator",'S', "SEP", 0, "String to separate multiple listings"},
+ {"prefix", 'P', "PFX", 0, "String to proceed listings; the first and second"
+ " occurances of %s are replace by HOST and DIR"},
+ {"host", 'h', "HOST",0, "Use HOST as a default host"},
+ {"debug", 'D', 0, 0, "Turn on debugging output for ftp connections"},
+ {"intepret", 'i', 0, 0, "Parse the directory output"},
+ {0, 0}
+};
+static char *args_doc = "[([HOST:]DIR | HOST:)...]";
+static char *doc = "Get a directory listing over ftp from HOST:DIR."
+"\vIf HOST is not supplied in an argument any default value set by --host is"
+" used; if DIR is not supplied, the default directory of HOST is used."
+"\nIf multiple DIRs are supplied on the command line, each listing is"
+" prefixed by a newline (or SEP) and a line containing HOST:DIR: (or PFX).";
+
+/* customization hooks. */
+static struct ftp_conn_hooks conn_hooks = { 0 };
+
+static void
+cntl_debug (struct ftp_conn *conn, int type, const char *txt)
+{
+ char *type_str;
+
+ switch (type)
+ {
+ case FTP_CONN_CNTL_DEBUG_CMD: type_str = "."; break;
+ case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
+ default: type_str = "?"; break;
+ }
+
+ fprintf (stderr, "%s%s\n", type_str, txt);
+}
+
+struct ftpdir_host
+{
+ char *name;
+ struct ftp_conn_params params;
+ struct ftp_conn *conn;
+ struct ftpdir_host *next;
+};
+
+/* Return an ftp connection for the host NAME using PARAMS, and add an entry
+ for it to *HOSTS. If a connection already exists in HOSTS, it is returned
+ instead of making a new one. If an error occurrs, a message is printed and
+ 0 is returned. */
+static struct ftpdir_host *
+get_host_conn (char *name, struct ftp_conn_params *params,
+ struct ftpdir_host **hosts)
+{
+ error_t err;
+ struct ftpdir_host *h;
+ struct hostent *he;
+
+ for (h = *hosts; h; h = h->next)
+ if (strcmp (h->name, name) == 0)
+ return h;
+
+ he = gethostbyname (name);
+ if (! he)
+ {
+ error (0, 0, "%s: %s", name, hstrerror (h_errno));
+ return 0;
+ }
+
+ for (h = *hosts; h; h = h->next)
+ if (he->h_addrtype == h->params.addr_type
+ && he->h_length == h->params.addr_len
+ && bcmp (he->h_addr_list[0], h->params.addr, he->h_length) == 0)
+ return h;
+
+ h = malloc (sizeof (struct ftpdir_host));
+ if (! h)
+ {
+ error (0, ENOMEM, "%s", name);
+ return 0;
+ }
+
+ h->params = *params;
+ h->params.addr = malloc (he->h_length);
+ h->name = strdup (he->h_name);
+
+ if (!h->name || !h->params.addr)
+ err = ENOMEM;
+ else
+ {
+ bcopy (he->h_addr_list[0], h->params.addr, he->h_length);
+ h->params.addr_len = he->h_length;
+ h->params.addr_type = he->h_addrtype;
+ err = ftp_conn_create (&h->params, &conn_hooks, &h->conn);
+ }
+
+ if (err)
+ {
+ error (0, err, "%s", he->h_name);
+ if (h->name)
+ free (h->name);
+ if (h->params.addr)
+ free (h->params.addr);
+ free (h);
+ return 0;
+ }
+
+ h->next = *hosts;
+ *hosts = h;
+
+ return h;
+}
+
+static int
+ftpdir (char *dir, struct ftpdir_host *host)
+{
+ int data;
+ int rd;
+ error_t err;
+ static void *copy_buf = 0;
+ struct ftp_conn *conn = host->conn;
+ char *host_name = host->name;
+
+ err = ftp_conn_start_dir (conn, dir, &data);
+ if (err)
+ {
+ error (0, err, "%s:%s", host_name, dir);
+ return err;
+ }
+
+ if (! copy_buf)
+ {
+ copy_buf = valloc (COPY_SZ);
+ if (! copy_buf)
+ error (12, ENOMEM, "Cannot allocate copy buffer");
+ }
+
+ while ((rd = read (data, copy_buf, COPY_SZ)) > 0)
+ do
+ {
+ int wr = write (1, copy_buf, rd);
+ if (wr < 0)
+ error (13, errno, "stdout");
+ rd -= wr;
+ }
+ while (rd > 0);
+ if (rd != 0)
+ {
+ error (0, errno, "%s:%s", host_name, dir);
+ return errno;
+ }
+
+ close (data);
+
+ err = ftp_conn_finish_transfer (conn);
+ if (err)
+ {
+ error (0, err, "%s:%s", host_name, dir);
+ return err;
+ }
+
+ return 0;
+}
+
+static error_t
+pdirent (const char *name, const struct stat *st, const char *symlink_target,
+ void *hook)
+{
+ char timebuf[20];
+ strftime (timebuf, sizeof timebuf, "%Y-%m-%d %H:%M", localtime (&st->st_mtime));
+ printf ("%6o %2d %5d %5d %6ld %s %s\n",
+ st->st_mode, st->st_nlink, st->st_uid, st->st_gid, st->st_size,
+ timebuf, name);
+ if (symlink_target)
+ printf (" -> %s\n",
+ symlink_target);
+ return 0;
+}
+
+static error_t
+ftpdir2 (char *dir, struct ftpdir_host *host)
+{
+ error_t err = ftp_conn_get_stats (host->conn, dir, 1, pdirent, 0);
+ if (err == ENOTDIR)
+ err = ftp_conn_get_stats (host->conn, dir, 0, pdirent, 0);
+ if (err)
+ error (0, err, "%s:%s", host->name, dir);
+ return err;
+}
+
+int
+main (int argc, char **argv)
+{
+ struct ftpdir_host *hosts = 0;
+ char *default_host = 0;
+ int interpret = 0;
+ struct ftp_conn_params params = { 0 };
+ char *sep = "\n";
+ char *pfx = "%s:%s:\n";
+ int use_pfx = 0;
+ int errs = 0;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ {
+ char *host, *dir;
+
+ if (state->next < state->argc)
+ use_pfx = 1; /* Multiple arguments. */
+
+ dir = index (arg, ':');
+ if (dir)
+ {
+ host = arg;
+ *dir++ = '\0';
+ if (*host == '\0')
+ /* An argument of `:' */
+ host = default_host;
+ }
+ else
+ {
+ host = default_host;
+ dir = arg;
+ }
+
+ if (host)
+ {
+ struct ftpdir_host *h = get_host_conn (host, &params, &hosts);
+ if (h)
+ {
+ if (state->arg_num > 0)
+ fputs (sep, stdout);
+ if (use_pfx)
+ printf (pfx, h->name, dir);
+ if (interpret)
+ errs |= ftpdir2 (dir, h);
+ else
+ errs |= ftpdir (dir, h);
+ }
+ errs = 1;
+ }
+ else
+ {
+ error (0, 0, "%s: No default host", arg);
+ errs = 1;
+ }
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (default_host)
+ {
+ struct ftpdir_host *h =
+ get_host_conn (default_host, &params, &hosts);
+ if (h)
+ errs |= ftpdir (0, h);
+ }
+ else
+ {
+ error (0, 0, "No default host");
+ errs = 1;
+ }
+ break;
+
+ return EINVAL;
+
+ case 'u': params.user = arg; break;
+ case 'p': params.pass = arg; break;
+ case 'a': params.acct = arg; break;
+ case 'h': default_host = arg; break;
+ case 'D': conn_hooks.cntl_debug = cntl_debug; break;
+ case 'P': pfx = arg; use_pfx = 1; break;
+ case 'S': sep = arg; break;
+ case 'i': interpret = 1; break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (errs)
+ exit (10);
+ else
+ exit (0);
+}