ftp.c
author Sunil Nimmagadda <sunil@nimmagadda.net>
Tue, 06 Dec 2022 13:51:55 +0000
changeset 0 1d0ce1ebbc72
permissions -rw-r--r--
An HTTP(S), FTP client. Found a copy of some old OpenBSD days hacking stashed somewhere in the backups. This version saw the light of the day as official OpenBSD ftp(1) for a grand total of 1 day :-)
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     1
/*
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     2
 * Copyright (c) 2015 Sunil Nimmagadda <sunil@openbsd.org>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     3
 *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     4
 * Permission to use, copy, modify, and distribute this software for any
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     5
 * purpose with or without fee is hereby granted, provided that the above
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     6
 * copyright notice and this permission notice appear in all copies.
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     7
 *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     8
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
     9
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    10
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    11
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    12
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    13
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    14
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    15
 */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    16
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    17
#include <sys/socket.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    18
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    19
#include <arpa/inet.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    20
#include <netinet/in.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    21
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    22
#include <err.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    23
#include <errno.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    24
#include <libgen.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    25
#include <limits.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    26
#include <netdb.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    27
#include <stdarg.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    28
#include <stdio.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    29
#include <stdint.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    30
#include <stdlib.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    31
#include <string.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    32
#include <unistd.h>
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    33
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    34
#include "ftp.h"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    35
#include "xmalloc.h"
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    36
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    37
static FILE	*ctrl_fp;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    38
static int	 data_fd;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    39
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    40
void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    41
ftp_connect(struct url *url, int timeout)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    42
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    43
	char		*buf = NULL;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    44
	size_t		 n = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    45
	int		 sock;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    46
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    47
	if ((sock = tcp_connect(url->host, url->port, timeout)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    48
		exit(1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    49
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    50
	if ((ctrl_fp = fdopen(sock, "r+")) == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    51
		err(1, "%s: fdopen", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    52
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    53
	/* greeting */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    54
	if (ftp_getline(&buf, &n, 0, ctrl_fp) != P_OK) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    55
		warnx("Can't connect to host `%s'", url->host);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    56
		ftp_command(ctrl_fp, "QUIT");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    57
		exit(1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    58
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    59
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    60
	free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    61
	log_info("Connected to %s\n", url->host);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    62
	if (ftp_auth(ctrl_fp, NULL, NULL) != P_OK) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    63
		warnx("Can't login to host `%s'", url->host);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    64
		ftp_command(ctrl_fp, "QUIT");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    65
		exit(1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    66
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    67
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    68
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    69
struct url *
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    70
ftp_get(struct url *url, off_t *offset, off_t *sz)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    71
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    72
	char	*buf = NULL, *dir, *file;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    73
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    74
	log_info("Using binary mode to transfer files.\n");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    75
	if (ftp_command(ctrl_fp, "TYPE I") != P_OK)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    76
		errx(1, "Failed to set mode to binary");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    77
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    78
	dir = dirname(url->path);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    79
	if (ftp_command(ctrl_fp, "CWD %s", dir) != P_OK)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    80
		errx(1, "CWD command failed");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    81
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    82
	log_info("Retrieving %s\n", url->path);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    83
	file = basename(url->path);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    84
	if (oarg && strcmp(oarg, "-") == 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    85
		log_info("remote: %s\n", file);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    86
	else
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    87
		log_info("local: %s remote: %s\n", oarg ? oarg : file , file);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    88
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    89
	if (ftp_size(ctrl_fp, file, sz, &buf) != P_OK) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    90
		fprintf(stderr, "%s", buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    91
		ftp_command(ctrl_fp, "QUIT");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    92
		exit(1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    93
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    94
	free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    95
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    96
	if (activemode)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    97
		data_fd = ftp_eprt(ctrl_fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    98
	else if ((data_fd = ftp_epsv(ctrl_fp)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
    99
		data_fd = ftp_eprt(ctrl_fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   100
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   101
	if (data_fd == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   102
		errx(1, "Failed to establish data connection");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   103
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   104
	if (*offset && ftp_command(ctrl_fp, "REST %lld", *offset) != P_INTER)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   105
		errx(1, "REST command failed");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   106
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   107
	if (ftp_command(ctrl_fp, "RETR %s", file) != P_PRE) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   108
		ftp_command(ctrl_fp, "QUIT");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   109
		exit(1);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   110
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   111
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   112
	return url;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   113
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   114
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   115
void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   116
ftp_save(struct url *url, FILE *dst_fp, off_t *offset)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   117
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   118
	struct sockaddr_storage	 ss;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   119
	FILE			*data_fp;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   120
	socklen_t		 len;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   121
	int			 s;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   122
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   123
	if (activemode) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   124
		len = sizeof(ss);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   125
		if ((s = accept(data_fd, (struct sockaddr *)&ss, &len)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   126
			err(1, "%s: accept", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   127
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   128
		close(data_fd);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   129
		data_fd = s;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   130
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   131
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   132
	if ((data_fp = fdopen(data_fd, "r")) == NULL)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   133
		err(1, "%s: fdopen data_fd", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   134
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   135
	copy_file(dst_fp, data_fp, offset);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   136
	fclose(data_fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   137
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   138
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   139
void
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   140
ftp_close(struct url *url)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   141
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   142
	char	*buf = NULL;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   143
	size_t	 n = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   144
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   145
	/*
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   146
	 * Reading reply here after progressmeter stops.
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   147
	 */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   148
	if (ftp_getline(&buf, &n, 0, ctrl_fp) != P_OK)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   149
		errx(1, "%s: %s", __func__, buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   150
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   151
	free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   152
	ftp_command(ctrl_fp, "QUIT");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   153
	fclose(ctrl_fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   154
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   155
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   156
int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   157
ftp_getline(char **lineptr, size_t *n, int suppress_output, FILE *fp)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   158
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   159
	ssize_t		 len;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   160
	char		*bufp, code[4];
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   161
	const char	*errstr;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   162
	int		 lookup[] = { P_PRE, P_OK, P_INTER, N_TRANS, N_PERM };
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   163
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   164
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   165
	if ((len = getline(lineptr, n, fp)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   166
		err(1, "%s: getline", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   167
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   168
	bufp = *lineptr;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   169
	if (!suppress_output)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   170
		log_info("%s", bufp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   171
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   172
	if (len < 4)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   173
		errx(1, "%s: line too short", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   174
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   175
	(void)strlcpy(code, bufp, sizeof code);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   176
	if (bufp[3] == ' ')
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   177
		goto done;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   178
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   179
	/* multi-line reply */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   180
	while (!(strncmp(code, bufp, 3) == 0 && bufp[3] == ' ')) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   181
		if ((len = getline(lineptr, n, fp)) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   182
			err(1, "%s: getline", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   183
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   184
		bufp = *lineptr;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   185
		if (!suppress_output)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   186
			log_info("%s", bufp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   187
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   188
		if (len < 4)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   189
			continue;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   190
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   191
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   192
 done:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   193
	(void)strtonum(code, 100, 553, &errstr);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   194
	if (errstr)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   195
		errx(1, "%s: Response code is %s: %s", __func__, errstr, code);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   196
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   197
	return lookup[code[0] - '1'];
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   198
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   199
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   200
int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   201
ftp_command(FILE *fp, const char *fmt, ...)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   202
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   203
	va_list	 ap;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   204
	char	*buf = NULL, *cmd;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   205
	size_t	 n = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   206
	int	 r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   207
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   208
	va_start(ap, fmt);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   209
	r = vasprintf(&cmd, fmt, ap);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   210
	va_end(ap);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   211
	if (r < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   212
		errx(1, "%s: vasprintf", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   213
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   214
	if (io_debug)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   215
		fprintf(stderr, ">>> %s\n", cmd);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   216
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   217
	if (fprintf(fp, "%s\r\n", cmd) < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   218
		errx(1, "%s: fprintf", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   219
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   220
	(void)fflush(fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   221
	free(cmd);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   222
	r = ftp_getline(&buf, &n, 0, fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   223
	free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   224
	return r;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   225
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   226
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   227
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   228
int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   229
ftp_auth(FILE *fp, const char *user, const char *pass)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   230
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   231
	char	*addr = NULL, hn[HOST_NAME_MAX+1], *un;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   232
	int	 code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   233
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   234
	code = ftp_command(fp, "USER %s", user ? user : "anonymous");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   235
	if (code != P_OK && code != P_INTER)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   236
		return code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   237
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   238
	if (pass == NULL) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   239
		if (gethostname(hn, sizeof hn) == -1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   240
			err(1, "%s: gethostname", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   241
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   242
		un = getlogin();
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   243
		xasprintf(&addr, "%s@%s", un ? un : "anonymous", hn);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   244
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   245
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   246
	code = ftp_command(fp, "PASS %s", pass ? pass : addr);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   247
	free(addr);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   248
	return code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   249
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   250
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   251
int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   252
ftp_size(FILE *fp, const char *fn, off_t *sizep, char **buf)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   253
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   254
	size_t	 n = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   255
	off_t	 file_sz;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   256
	int	 code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   257
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   258
	if (io_debug)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   259
		fprintf(stderr, ">>> SIZE %s\n", fn);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   260
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   261
	if (fprintf(fp, "SIZE %s\r\n", fn) < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   262
		errx(1, "%s: fprintf", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   263
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   264
	(void)fflush(fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   265
	if ((code = ftp_getline(buf, &n, 1, fp)) != P_OK)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   266
		return code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   267
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   268
	if (sscanf(*buf, "%*u %lld", &file_sz) != 1)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   269
		errx(1, "%s: sscanf size", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   270
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   271
	if (file_sz < 0 || file_sz > INT64_MAX)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   272
		errx(1, "%s: size out of bounds: %lld", __func__, file_sz);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   273
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   274
	if (sizep)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   275
		*sizep = file_sz;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   276
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   277
	return code;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   278
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   279
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   280
int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   281
ftp_eprt(FILE *fp)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   282
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   283
	struct sockaddr_storage	 ss;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   284
	char			 addr[NI_MAXHOST], port[NI_MAXSERV], *eprt;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   285
	socklen_t		 len;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   286
	int			 e, on, ret, sock;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   287
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   288
	len = sizeof(ss);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   289
	memset(&ss, 0, len);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   290
	if (getsockname(fileno(fp), (struct sockaddr *)&ss, &len) == -1) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   291
		warn("%s: getsockname", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   292
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   293
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   294
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   295
	/* pick a free port */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   296
	switch (ss.ss_family) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   297
	case AF_INET:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   298
		((struct sockaddr_in *)&ss)->sin_port = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   299
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   300
	case AF_INET6:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   301
		((struct sockaddr_in6 *)&ss)->sin6_port = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   302
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   303
	default:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   304
		errx(1, "%s: Invalid socket family", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   305
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   306
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   307
	if ((sock = socket(ss.ss_family, SOCK_STREAM, 0)) == -1) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   308
		warn("%s: socket", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   309
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   310
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   311
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   312
	switch (ss.ss_family) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   313
	case AF_INET:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   314
		on = IP_PORTRANGE_HIGH;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   315
		if (setsockopt(sock, IPPROTO_IP, IP_PORTRANGE,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   316
		    (char *)&on, sizeof(on)) < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   317
			warn("setsockopt IP_PORTRANGE (ignored)");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   318
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   319
	case AF_INET6:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   320
		on = IPV6_PORTRANGE_HIGH;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   321
		if (setsockopt(sock, IPPROTO_IPV6, IPV6_PORTRANGE,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   322
		    (char *)&on, sizeof(on)) < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   323
			warn("setsockopt IPV6_PORTRANGE (ignored)");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   324
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   325
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   326
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   327
	if (bind(sock, (struct sockaddr *)&ss, len) == -1) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   328
		close(sock);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   329
		warn("%s: bind", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   330
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   331
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   332
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   333
	if (listen(sock, 1) == -1) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   334
		close(sock);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   335
		warn("%s: listen", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   336
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   337
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   338
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   339
	/* Find out the ephemeral port chosen */
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   340
	len = sizeof(ss);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   341
	memset(&ss, 0, len);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   342
	if (getsockname(sock, (struct sockaddr *)&ss, &len) == -1) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   343
		close(sock);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   344
		warn("%s: getsockname", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   345
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   346
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   347
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   348
	if ((e = getnameinfo((struct sockaddr *)&ss, len,
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   349
	    addr, sizeof(addr), port, sizeof(port),
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   350
	    NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   351
		close(sock);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   352
		warn("%s: getnameinfo: %s", __func__, gai_strerror(e));
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   353
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   354
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   355
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   356
	xasprintf(&eprt, "EPRT |%d|%s|%s|",
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   357
	    ss.ss_family == AF_INET ? 1 : 2, addr, port);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   358
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   359
	ret = ftp_command(fp, "%s", eprt);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   360
	free(eprt);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   361
	if (ret != P_OK) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   362
		close(sock);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   363
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   364
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   365
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   366
	return sock;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   367
}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   368
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   369
int
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   370
ftp_epsv(FILE *fp)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   371
{
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   372
	struct sockaddr_storage	 ss;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   373
	char			*buf = NULL, delim[4], *s, *e;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   374
	size_t			 n = 0;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   375
	socklen_t		 len;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   376
	int			 error, port, sock;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   377
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   378
	if (io_debug)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   379
		fprintf(stderr, ">>> EPSV\n");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   380
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   381
	if (fprintf(fp, "EPSV\r\n") < 0)
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   382
		errx(1, "%s: fprintf", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   383
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   384
	(void)fflush(fp);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   385
	if (ftp_getline(&buf, &n, 1, fp) != P_OK) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   386
		free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   387
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   388
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   389
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   390
	if ((s = strchr(buf, '(')) == NULL || (e = strchr(s, ')')) == NULL) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   391
		warnx("Malformed EPSV reply");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   392
		free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   393
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   394
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   395
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   396
	s++;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   397
	*e = '\0';
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   398
	if (sscanf(s, "%c%c%c%d%c", &delim[0], &delim[1], &delim[2],
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   399
	    &port, &delim[3]) != 5) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   400
		warnx("EPSV parse error");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   401
		free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   402
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   403
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   404
	free(buf);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   405
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   406
	if (delim[0] != delim[1] || delim[0] != delim[2]
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   407
	    || delim[0] != delim[3]) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   408
		warnx("EPSV parse error");
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   409
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   410
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   411
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   412
	len = sizeof(ss);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   413
	memset(&ss, 0, len);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   414
	if (getpeername(fileno(fp), (struct sockaddr *)&ss, &len) == -1) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   415
		warn("%s: getpeername", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   416
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   417
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   418
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   419
	switch (ss.ss_family) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   420
	case AF_INET:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   421
		((struct sockaddr_in *)&ss)->sin_port = htons(port);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   422
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   423
	case AF_INET6:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   424
		((struct sockaddr_in6 *)&ss)->sin6_port = htons(port);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   425
		break;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   426
	default:
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   427
		errx(1, "%s: Invalid socket family", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   428
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   429
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   430
	if ((sock = socket(ss.ss_family, SOCK_STREAM, 0)) == -1) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   431
		warn("%s: socket", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   432
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   433
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   434
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   435
	for (error = connect(sock, (struct sockaddr *)&ss, len);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   436
	     error != 0 && errno == EINTR; error = connect_wait(sock))
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   437
		continue;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   438
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   439
	if (error != 0) {
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   440
		warn("%s: connect", __func__);
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   441
		return -1;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   442
	}
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   443
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   444
	return sock;
1d0ce1ebbc72 An HTTP(S), FTP client.
Sunil Nimmagadda <sunil@nimmagadda.net>
parents:
diff changeset
   445
}