NetBSD/usr.bin/ftp/ftp.c

1598 lines
33 KiB
C
Raw Normal View History

/* $NetBSD: ftp.c,v 1.31 1998/01/18 14:23:36 lukem Exp $ */
1995-09-08 05:05:59 +04:00
1993-03-21 12:45:37 +03:00
/*
1994-08-25 07:47:50 +04:00
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
1993-03-21 12:45:37 +03:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
1993-03-21 12:45:37 +03:00
#ifndef lint
1995-09-08 05:05:59 +04:00
#if 0
static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
#else
__RCSID("$NetBSD: ftp.c,v 1.31 1998/01/18 14:23:36 lukem Exp $");
1995-09-08 05:05:59 +04:00
#endif
1993-03-21 12:45:37 +03:00
#endif /* not lint */
#include <sys/types.h>
1993-03-21 12:45:37 +03:00
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
1994-08-25 07:47:50 +04:00
#include <arpa/inet.h>
1993-03-21 12:45:37 +03:00
#include <arpa/ftp.h>
#include <arpa/telnet.h>
1994-08-25 07:47:50 +04:00
#include <ctype.h>
#include <err.h>
1993-03-21 12:45:37 +03:00
#include <errno.h>
1994-08-25 07:47:50 +04:00
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef __STDC__
#include <stdarg.h>
#else
1993-03-21 12:45:37 +03:00
#include <varargs.h>
#endif
1993-03-21 12:45:37 +03:00
#include "ftp_var.h"
struct sockaddr_in hisctladdr;
struct sockaddr_in data_addr;
int data = -1;
int abrtflag = 0;
1994-08-25 07:47:50 +04:00
jmp_buf ptabort;
int ptabflg;
1993-03-21 12:45:37 +03:00
int ptflag = 0;
struct sockaddr_in myctladdr;
FILE *cin, *cout;
char *
hookup(host, port)
const char *host;
in_port_t port;
1993-03-21 12:45:37 +03:00
{
struct hostent *hp = NULL;
1993-03-21 12:45:37 +03:00
int s, len, tos;
static char hostnamebuf[MAXHOSTNAMELEN];
1993-03-21 12:45:37 +03:00
memset((void *)&hisctladdr, 0, sizeof(hisctladdr));
1995-05-21 19:50:45 +04:00
if (inet_aton(host, &hisctladdr.sin_addr) != 0) {
1993-03-21 12:45:37 +03:00
hisctladdr.sin_family = AF_INET;
(void)strncpy(hostnamebuf, host, sizeof(hostnamebuf) - 1);
hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
1993-03-21 12:45:37 +03:00
} else {
hp = gethostbyname(host);
if (hp == NULL) {
1994-08-25 07:47:50 +04:00
warnx("%s: %s", host, hstrerror(h_errno));
1993-03-21 12:45:37 +03:00
code = -1;
return (NULL);
1993-03-21 12:45:37 +03:00
}
hisctladdr.sin_family = hp->h_addrtype;
1995-05-21 19:50:45 +04:00
memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
(void)strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf) - 1);
hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
1993-03-21 12:45:37 +03:00
}
hostname = hostnamebuf;
s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
if (s < 0) {
1994-08-25 07:47:50 +04:00
warn("socket");
1993-03-21 12:45:37 +03:00
code = -1;
return (0);
}
hisctladdr.sin_port = port;
while (connect(s, (struct sockaddr *)&hisctladdr,
sizeof(hisctladdr)) < 0) {
1993-03-21 12:45:37 +03:00
if (hp && hp->h_addr_list[1]) {
int oerrno = errno;
1994-08-25 07:47:50 +04:00
char *ia;
1993-03-21 12:45:37 +03:00
1994-08-25 07:47:50 +04:00
ia = inet_ntoa(hisctladdr.sin_addr);
1993-03-21 12:45:37 +03:00
errno = oerrno;
1994-08-25 07:47:50 +04:00
warn("connect to address %s", ia);
1993-03-21 12:45:37 +03:00
hp->h_addr_list++;
memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
printf("Trying %s...\n",
inet_ntoa(hisctladdr.sin_addr));
(void)close(s);
1993-03-21 12:45:37 +03:00
s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
if (s < 0) {
1994-08-25 07:47:50 +04:00
warn("socket");
1993-03-21 12:45:37 +03:00
code = -1;
return (0);
}
continue;
}
1994-08-25 07:47:50 +04:00
warn("connect");
1993-03-21 12:45:37 +03:00
code = -1;
goto bad;
}
len = sizeof(myctladdr);
1993-03-21 12:45:37 +03:00
if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
1994-08-25 07:47:50 +04:00
warn("getsockname");
1993-03-21 12:45:37 +03:00
code = -1;
goto bad;
}
#ifdef IP_TOS
tos = IPTOS_LOWDELAY;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1994-08-25 07:47:50 +04:00
warn("setsockopt TOS (ignored)");
1993-03-21 12:45:37 +03:00
#endif
cin = fdopen(s, "r");
cout = fdopen(s, "w");
if (cin == NULL || cout == NULL) {
1994-08-25 07:47:50 +04:00
warnx("fdopen failed.");
1993-03-21 12:45:37 +03:00
if (cin)
(void)fclose(cin);
1993-03-21 12:45:37 +03:00
if (cout)
(void)fclose(cout);
1993-03-21 12:45:37 +03:00
code = -1;
goto bad;
}
if (verbose)
printf("Connected to %s.\n", hostname);
if (getreply(0) > 2) { /* read startup message from server */
if (cin)
(void)fclose(cin);
1993-03-21 12:45:37 +03:00
if (cout)
(void)fclose(cout);
1993-03-21 12:45:37 +03:00
code = -1;
goto bad;
}
#ifdef SO_OOBINLINE
{
int on = 1;
if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
< 0 && debug) {
1994-08-25 07:47:50 +04:00
warn("setsockopt");
1993-03-21 12:45:37 +03:00
}
}
#endif /* SO_OOBINLINE */
return (hostname);
bad:
(void)close(s);
return (NULL);
1993-03-21 12:45:37 +03:00
}
void
cmdabort(notused)
int notused;
1993-03-21 12:45:37 +03:00
{
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
alarmtimer(0);
putchar('\n');
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
abrtflag++;
if (ptflag)
longjmp(ptabort, 1);
1993-03-21 12:45:37 +03:00
}
/*VARARGS*/
1994-08-25 07:47:50 +04:00
int
#ifdef __STDC__
command(const char *fmt, ...)
#else
1993-03-21 12:45:37 +03:00
command(va_alist)
va_dcl
#endif
1993-03-21 12:45:37 +03:00
{
va_list ap;
int r;
sig_t oldintr;
#ifndef __STDC__
const char *fmt;
#endif
1993-03-21 12:45:37 +03:00
abrtflag = 0;
if (debug) {
fputs("---> ", stdout);
#ifdef __STDC__
va_start(ap, fmt);
#else
1993-03-21 12:45:37 +03:00
va_start(ap);
fmt = va_arg(ap, const char *);
#endif
1993-03-21 12:45:37 +03:00
if (strncmp("PASS ", fmt, 5) == 0)
fputs("PASS XXXX", stdout);
else if (strncmp("ACCT ", fmt, 5) == 0)
fputs("ACCT XXXX", stdout);
else
vprintf(fmt, ap);
1993-03-21 12:45:37 +03:00
va_end(ap);
putchar('\n');
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
if (cout == NULL) {
warnx("No control connection for command.");
1993-03-21 12:45:37 +03:00
code = -1;
return (0);
}
oldintr = signal(SIGINT, cmdabort);
#ifdef __STDC__
va_start(ap, fmt);
#else
1993-03-21 12:45:37 +03:00
va_start(ap);
fmt = va_arg(ap, char *);
#endif
1993-03-21 12:45:37 +03:00
vfprintf(cout, fmt, ap);
va_end(ap);
fputs("\r\n", cout);
(void)fflush(cout);
1993-03-21 12:45:37 +03:00
cpend = 1;
r = getreply(!strcmp(fmt, "QUIT"));
if (abrtflag && oldintr != SIG_IGN)
(*oldintr)(SIGINT);
(void)signal(SIGINT, oldintr);
1994-08-25 07:47:50 +04:00
return (r);
1993-03-21 12:45:37 +03:00
}
char reply_string[BUFSIZ]; /* first line of previous reply */
1993-03-21 12:45:37 +03:00
1994-08-25 07:47:50 +04:00
int
1993-03-21 12:45:37 +03:00
getreply(expecteof)
int expecteof;
{
char current_line[BUFSIZ]; /* last line of previous reply */
int c, n, line;
1994-08-25 07:47:50 +04:00
int dig;
1993-03-21 12:45:37 +03:00
int originalcode = 0, continuation = 0;
sig_t oldintr;
int pflag = 0;
1994-08-25 07:47:50 +04:00
char *cp, *pt = pasv;
1993-03-21 12:45:37 +03:00
oldintr = signal(SIGINT, cmdabort);
for (line = 0 ;; line++) {
1993-03-21 12:45:37 +03:00
dig = n = code = 0;
cp = current_line;
1993-03-21 12:45:37 +03:00
while ((c = getc(cin)) != '\n') {
if (c == IAC) { /* handle telnet commands */
switch (c = getc(cin)) {
case WILL:
case WONT:
c = getc(cin);
fprintf(cout, "%c%c%c", IAC, DONT, c);
(void)fflush(cout);
1993-03-21 12:45:37 +03:00
break;
case DO:
case DONT:
c = getc(cin);
fprintf(cout, "%c%c%c", IAC, WONT, c);
(void)fflush(cout);
1993-03-21 12:45:37 +03:00
break;
default:
break;
}
continue;
}
dig++;
if (c == EOF) {
if (expecteof) {
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
code = 221;
return (0);
}
lostpeer();
if (verbose) {
puts(
"421 Service not available, remote server has closed connection.");
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
code = 421;
1994-08-25 07:47:50 +04:00
return (4);
1993-03-21 12:45:37 +03:00
}
if (c != '\r' && (verbose > 0 ||
(verbose > -1 && n == '5' && dig > 4))) {
if (proxflag &&
(dig == 1 || (dig == 5 && verbose == 0)))
printf("%s:", hostname);
(void)putchar(c);
1993-03-21 12:45:37 +03:00
}
if (dig < 4 && isdigit(c))
code = code * 10 + (c - '0');
if (!pflag && code == 227)
pflag = 1;
if (dig > 4 && pflag == 1 && isdigit(c))
pflag = 2;
if (pflag == 2) {
if (c != '\r' && c != ')')
*pt++ = c;
else {
*pt = '\0';
pflag = 3;
}
}
if (dig == 4 && c == '-') {
if (continuation)
code = 0;
continuation++;
}
if (n == 0)
n = c;
if (cp < &current_line[sizeof(current_line) - 1])
1993-03-21 12:45:37 +03:00
*cp++ = c;
}
if (verbose > 0 || (verbose > -1 && n == '5')) {
(void)putchar(c);
(void)fflush (stdout);
1993-03-21 12:45:37 +03:00
}
if (line == 0) {
size_t len = cp - current_line;
if (len > sizeof(reply_string))
len = sizeof(reply_string);
(void)strncpy(reply_string, current_line, len);
reply_string[len] = '\0';
}
1993-03-21 12:45:37 +03:00
if (continuation && code != originalcode) {
if (originalcode == 0)
originalcode = code;
continue;
}
*cp = '\0';
if (n != '1')
cpend = 0;
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
if (code == 421 || originalcode == 421)
lostpeer();
if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
(*oldintr)(SIGINT);
return (n - '0');
}
}
1994-08-25 07:47:50 +04:00
int
1993-03-21 12:45:37 +03:00
empty(mask, sec)
struct fd_set *mask;
int sec;
{
struct timeval t;
t.tv_sec = (long) sec;
t.tv_usec = 0;
return (select(32, mask, NULL, NULL, &t));
1993-03-21 12:45:37 +03:00
}
jmp_buf sendabort;
void
abortsend(notused)
int notused;
1993-03-21 12:45:37 +03:00
{
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
alarmtimer(0);
1993-03-21 12:45:37 +03:00
mflag = 0;
abrtflag = 0;
puts("\nsend aborted\nwaiting for remote to finish abort.");
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
longjmp(sendabort, 1);
}
1994-08-25 07:47:50 +04:00
void
1993-03-21 12:45:37 +03:00
sendrequest(cmd, local, remote, printnames)
const char *cmd, *local, *remote;
1993-03-21 12:45:37 +03:00
int printnames;
{
struct stat st;
1994-08-25 07:47:50 +04:00
int c, d;
FILE *fin, *dout;
1994-08-25 07:47:50 +04:00
int (*closefunc) __P((FILE *));
sig_t oldinti, oldintr, oldintp;
volatile off_t hashbytes;
1993-03-21 12:45:37 +03:00
char *lmode, buf[BUFSIZ], *bufp;
int oprogress;
1993-03-21 12:45:37 +03:00
#ifdef __GNUC__ /* XXX: to shut up gcc warnings */
(void)&fin;
(void)&dout;
(void)&closefunc;
(void)&oldinti;
(void)&oldintr;
(void)&oldintp;
(void)&lmode;
#endif
hashbytes = mark;
direction = "sent";
dout = NULL;
bytes = 0;
filesize = -1;
oprogress = progress;
1993-03-21 12:45:37 +03:00
if (verbose && printnames) {
if (local && *local != '-')
printf("local: %s ", local);
if (remote)
printf("remote: %s\n", remote);
}
if (proxy) {
proxtrans(cmd, local, remote);
return;
}
if (curtype != type)
changetype(type, 0);
closefunc = NULL;
oldintr = NULL;
oldintp = NULL;
oldinti = NULL;
1993-03-21 12:45:37 +03:00
lmode = "w";
if (setjmp(sendabort)) {
while (cpend) {
(void)getreply(0);
1993-03-21 12:45:37 +03:00
}
if (data >= 0) {
(void)close(data);
1993-03-21 12:45:37 +03:00
data = -1;
}
if (oldintr)
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
if (oldinti)
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
oldintr = signal(SIGINT, abortsend);
oldinti = signal(SIGINFO, psummary);
if (strcmp(local, "-") == 0) {
1993-03-21 12:45:37 +03:00
fin = stdin;
progress = 0;
} else if (*local == '|') {
oldintp = signal(SIGPIPE, SIG_IGN);
1993-03-21 12:45:37 +03:00
fin = popen(local + 1, "r");
if (fin == NULL) {
1994-08-25 07:47:50 +04:00
warn("%s", local + 1);
(void)signal(SIGINT, oldintr);
(void)signal(SIGPIPE, oldintp);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
progress = 0;
1993-03-21 12:45:37 +03:00
closefunc = pclose;
} else {
fin = fopen(local, "r");
if (fin == NULL) {
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
closefunc = fclose;
1997-10-19 23:09:05 +04:00
if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
printf("%s: not a plain file.\n", local);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
fclose(fin);
code = -1;
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
filesize = st.st_size;
1993-03-21 12:45:37 +03:00
}
if (initconn()) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
1993-03-21 12:45:37 +03:00
code = -1;
if (closefunc != NULL)
(*closefunc)(fin);
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
if (setjmp(sendabort))
goto abort;
if (restart_point &&
(strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
1994-08-25 07:47:50 +04:00
int rc;
rc = -1;
1994-08-25 07:47:50 +04:00
switch (curtype) {
case TYPE_A:
rc = fseek(fin, (long) restart_point, SEEK_SET);
break;
case TYPE_I:
case TYPE_L:
rc = lseek(fileno(fin), restart_point, SEEK_SET);
break;
}
if (rc < 0) {
warn("local: %s", local);
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fin);
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
if (command("REST %qd", (long long) restart_point) !=
CONTINUE) {
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fin);
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
lmode = "r+w";
}
if (remote) {
if (command("%s %s", cmd, remote) != PRELIM) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fin);
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
} else
if (command("%s", cmd) != PRELIM) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fin);
goto cleanupsend;
1993-03-21 12:45:37 +03:00
}
dout = dataconn(lmode);
if (dout == NULL)
goto abort;
progressmeter(-1);
1993-03-21 12:45:37 +03:00
oldintp = signal(SIGPIPE, SIG_IGN);
switch (curtype) {
case TYPE_I:
case TYPE_L:
errno = d = 0;
while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
1993-03-21 12:45:37 +03:00
bytes += c;
for (bufp = buf; c > 0; c -= d, bufp += d)
if ((d = write(fileno(dout), bufp, c)) <= 0)
break;
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
if (hash && (!progress || filesize < 0) ) {
1993-03-21 12:45:37 +03:00
while (bytes >= hashbytes) {
(void)putchar('#');
hashbytes += mark;
1993-03-21 12:45:37 +03:00
}
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
}
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
if (hash && (!progress || filesize < 0) && bytes > 0) {
if (bytes < mark)
(void)putchar('#');
(void)putchar('\n');
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
if (c < 0)
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
1993-03-21 12:45:37 +03:00
if (d < 0) {
if (errno != EPIPE)
1994-08-25 07:47:50 +04:00
warn("netout");
1993-03-21 12:45:37 +03:00
bytes = -1;
}
break;
case TYPE_A:
while ((c = getc(fin)) != EOF) {
if (c == '\n') {
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
while (hash && (!progress || filesize < 0) &&
(bytes >= hashbytes)) {
(void)putchar('#');
(void)fflush(stdout);
hashbytes += mark;
1993-03-21 12:45:37 +03:00
}
if (ferror(dout))
break;
(void)putc('\r', dout);
1993-03-21 12:45:37 +03:00
bytes++;
}
(void)putc(c, dout);
1993-03-21 12:45:37 +03:00
bytes++;
#if 0 /* this violates RFC */
if (c == '\r') {
(void)putc('\0', dout);
bytes++;
}
#endif
1993-03-21 12:45:37 +03:00
}
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
if (hash && (!progress || filesize < 0)) {
1993-03-21 12:45:37 +03:00
if (bytes < hashbytes)
(void)putchar('#');
(void)putchar('\n');
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
if (ferror(fin))
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
1993-03-21 12:45:37 +03:00
if (ferror(dout)) {
if (errno != EPIPE)
1994-08-25 07:47:50 +04:00
warn("netout");
1993-03-21 12:45:37 +03:00
bytes = -1;
}
break;
}
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
progressmeter(1);
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fin);
(void)fclose(dout);
(void)getreply(0);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
1993-03-21 12:45:37 +03:00
if (bytes > 0)
ptransfer(0);
goto cleanupsend;
1993-03-21 12:45:37 +03:00
abort:
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
1993-03-21 12:45:37 +03:00
if (!cpend) {
code = -1;
return;
}
if (data >= 0) {
(void)close(data);
1993-03-21 12:45:37 +03:00
data = -1;
}
if (dout)
(void)fclose(dout);
(void)getreply(0);
1993-03-21 12:45:37 +03:00
code = -1;
if (closefunc != NULL && fin != NULL)
(*closefunc)(fin);
if (bytes > 0)
ptransfer(0);
cleanupsend:
progress = oprogress;
restart_point = 0;
1993-03-21 12:45:37 +03:00
}
jmp_buf recvabort;
void
abortrecv(notused)
int notused;
1993-03-21 12:45:37 +03:00
{
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
alarmtimer(0);
1993-03-21 12:45:37 +03:00
mflag = 0;
abrtflag = 0;
puts("\nreceive aborted\nwaiting for remote to finish abort.");
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
longjmp(recvabort, 1);
}
1994-08-25 07:47:50 +04:00
void
recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
const char *cmd, *local, *remote, *lmode;
int printnames, ignorespecial;
1993-03-21 12:45:37 +03:00
{
FILE *fout, *din;
1994-08-25 07:47:50 +04:00
int (*closefunc) __P((FILE *));
sig_t oldinti, oldintr, oldintp;
int c, d;
volatile int is_retr, tcrflag, bare_lfs;
static size_t bufsize;
1993-03-21 12:45:37 +03:00
static char *buf;
volatile off_t hashbytes;
1993-03-21 12:45:37 +03:00
struct stat st;
time_t mtime;
struct timeval tval[2];
int oprogress;
int opreserve;
1993-03-21 12:45:37 +03:00
#ifdef __GNUC__ /* XXX: to shut up gcc warnings */
(void)&local;
(void)&fout;
(void)&din;
(void)&closefunc;
(void)&oldinti;
(void)&oldintr;
(void)&oldintp;
#endif
fout = NULL;
din = NULL;
oldinti = NULL;
hashbytes = mark;
direction = "received";
bytes = 0;
bare_lfs = 0;
filesize = -1;
oprogress = progress;
opreserve = preserve;
is_retr = (strcmp(cmd, "RETR") == 0);
1993-03-21 12:45:37 +03:00
if (is_retr && verbose && printnames) {
if (local && (ignorespecial || *local != '-'))
1993-03-21 12:45:37 +03:00
printf("local: %s ", local);
if (remote)
printf("remote: %s\n", remote);
}
if (proxy && is_retr) {
proxtrans(cmd, local, remote);
return;
}
closefunc = NULL;
oldintr = NULL;
oldintp = NULL;
tcrflag = !crflag && is_retr;
if (setjmp(recvabort)) {
while (cpend) {
(void)getreply(0);
1993-03-21 12:45:37 +03:00
}
if (data >= 0) {
(void)close(data);
1993-03-21 12:45:37 +03:00
data = -1;
}
if (oldintr)
(void)signal(SIGINT, oldintr);
if (oldinti)
(void)signal(SIGINFO, oldinti);
progress = oprogress;
preserve = opreserve;
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
oldintr = signal(SIGINT, abortrecv);
oldinti = signal(SIGINFO, psummary);
if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
if (access(local, W_OK) < 0) {
1994-08-25 07:47:50 +04:00
char *dir = strrchr(local, '/');
1993-03-21 12:45:37 +03:00
if (errno != ENOENT && errno != EACCES) {
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
if (dir != NULL)
*dir = 0;
d = access(dir == local ? "/" : dir ? local : ".", W_OK);
1993-03-21 12:45:37 +03:00
if (dir != NULL)
*dir = '/';
if (d < 0) {
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
if (!runique && errno == EACCES &&
chmod(local, 0600) < 0) {
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
if (runique && errno == EACCES &&
(local = gunique(local)) == NULL) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
}
else if (runique && (local = gunique(local)) == NULL) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
}
if (!is_retr) {
if (curtype != TYPE_A)
changetype(TYPE_A, 0);
} else {
if (curtype != type)
changetype(type, 0);
filesize = remotesize(remote, 0);
}
1993-03-21 12:45:37 +03:00
if (initconn()) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
if (setjmp(recvabort))
goto abort;
if (is_retr && restart_point &&
command("REST %qd", (long long) restart_point) != CONTINUE)
1993-03-21 12:45:37 +03:00
return;
if (remote) {
if (command("%s %s", cmd, remote) != PRELIM) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
return;
}
} else {
if (command("%s", cmd) != PRELIM) {
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
return;
}
}
din = dataconn("r");
if (din == NULL)
goto abort;
if (!ignorespecial && strcmp(local, "-") == 0) {
1993-03-21 12:45:37 +03:00
fout = stdout;
progress = 0;
preserve = 0;
} else if (!ignorespecial && *local == '|') {
1993-03-21 12:45:37 +03:00
oldintp = signal(SIGPIPE, SIG_IGN);
fout = popen(local + 1, "w");
if (fout == NULL) {
1994-08-25 07:47:50 +04:00
warn("%s", local+1);
1993-03-21 12:45:37 +03:00
goto abort;
}
progress = 0;
preserve = 0;
1993-03-21 12:45:37 +03:00
closefunc = pclose;
} else {
fout = fopen(local, lmode);
if (fout == NULL) {
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
1993-03-21 12:45:37 +03:00
goto abort;
}
closefunc = fclose;
}
if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
st.st_blksize = BUFSIZ;
if (st.st_blksize > bufsize) {
if (buf)
(void)free(buf);
1993-03-21 12:45:37 +03:00
buf = malloc((unsigned)st.st_blksize);
if (buf == NULL) {
1994-08-25 07:47:50 +04:00
warn("malloc");
1993-03-21 12:45:37 +03:00
bufsize = 0;
goto abort;
}
bufsize = st.st_blksize;
}
1997-10-19 23:09:05 +04:00
if (!S_ISREG(st.st_mode)) {
progress = 0;
preserve = 0;
}
progressmeter(-1);
1993-03-21 12:45:37 +03:00
switch (curtype) {
case TYPE_I:
case TYPE_L:
if (is_retr && restart_point &&
1994-08-25 07:47:50 +04:00
lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
warn("local: %s", local);
progress = oprogress;
preserve = opreserve;
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fout);
return;
}
errno = d = 0;
while ((c = read(fileno(din), buf, bufsize)) > 0) {
if ((d = write(fileno(fout), buf, c)) != c)
break;
bytes += c;
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
if (hash && (!progress || filesize < 0)) {
1993-03-21 12:45:37 +03:00
while (bytes >= hashbytes) {
(void)putchar('#');
hashbytes += mark;
1993-03-21 12:45:37 +03:00
}
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
}
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
if (hash && (!progress || filesize < 0) && bytes > 0) {
if (bytes < mark)
(void)putchar('#');
(void)putchar('\n');
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
if (c < 0) {
if (errno != EPIPE)
1994-08-25 07:47:50 +04:00
warn("netin");
1993-03-21 12:45:37 +03:00
bytes = -1;
}
if (d < c) {
if (d < 0)
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
1993-03-21 12:45:37 +03:00
else
1994-08-25 07:47:50 +04:00
warnx("%s: short write", local);
1993-03-21 12:45:37 +03:00
}
break;
case TYPE_A:
if (is_retr && restart_point) {
int ch;
long i, n;
1993-03-21 12:45:37 +03:00
1994-08-25 07:47:50 +04:00
if (fseek(fout, 0L, SEEK_SET) < 0)
1993-03-21 12:45:37 +03:00
goto done;
n = (long)restart_point;
1993-03-21 12:45:37 +03:00
for (i = 0; i++ < n;) {
if ((ch = getc(fout)) == EOF)
goto done;
if (ch == '\n')
i++;
}
1994-08-25 07:47:50 +04:00
if (fseek(fout, 0L, SEEK_CUR) < 0) {
1993-03-21 12:45:37 +03:00
done:
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
progress = oprogress;
preserve = opreserve;
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fout);
return;
}
}
while ((c = getc(din)) != EOF) {
if (c == '\n')
bare_lfs++;
while (c == '\r') {
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
while (hash && (!progress || filesize < 0) &&
(bytes >= hashbytes)) {
(void)putchar('#');
(void)fflush(stdout);
hashbytes += mark;
1993-03-21 12:45:37 +03:00
}
bytes++;
if ((c = getc(din)) != '\n' || tcrflag) {
if (ferror(fout))
goto break2;
(void)putc('\r', fout);
1993-03-21 12:45:37 +03:00
if (c == '\0') {
bytes++;
goto contin2;
}
if (c == EOF)
goto contin2;
}
}
(void)putc(c, fout);
1993-03-21 12:45:37 +03:00
bytes++;
contin2: ;
}
break2:
if (bare_lfs) {
printf(
"WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
puts("File may not have transferred correctly.");
1993-03-21 12:45:37 +03:00
}
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
if (hash && (!progress || filesize < 0)) {
1993-03-21 12:45:37 +03:00
if (bytes < hashbytes)
(void)putchar('#');
(void)putchar('\n');
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
}
if (ferror(din)) {
if (errno != EPIPE)
1994-08-25 07:47:50 +04:00
warn("netin");
1993-03-21 12:45:37 +03:00
bytes = -1;
}
if (ferror(fout))
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
1993-03-21 12:45:37 +03:00
break;
}
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
progressmeter(1);
progress = oprogress;
preserve = opreserve;
1993-03-21 12:45:37 +03:00
if (closefunc != NULL)
(*closefunc)(fout);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
(void)fclose(din);
(void)getreply(0);
if (bytes >= 0 && is_retr) {
if (bytes > 0)
ptransfer(0);
if (preserve && (closefunc == fclose)) {
mtime = remotemodtime(remote, 0);
if (mtime != -1) {
(void)gettimeofday(&tval[0], NULL);
tval[1].tv_sec = mtime;
tval[1].tv_usec = 0;
if (utimes(local, tval) == -1) {
printf(
"Can't change modification time on %s to %s",
local, asctime(localtime(&mtime)));
}
}
}
}
1993-03-21 12:45:37 +03:00
return;
1993-03-21 12:45:37 +03:00
abort:
/* abort using RFC959 recommended IP,SYNC sequence */
1993-03-21 12:45:37 +03:00
progress = oprogress;
preserve = opreserve;
1993-03-21 12:45:37 +03:00
if (oldintp)
(void)signal(SIGPIPE, oldintp);
(void)signal(SIGINT, SIG_IGN);
1993-03-21 12:45:37 +03:00
if (!cpend) {
code = -1;
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
return;
}
abort_remote(din);
code = -1;
if (data >= 0) {
(void)close(data);
1993-03-21 12:45:37 +03:00
data = -1;
}
if (closefunc != NULL && fout != NULL)
(*closefunc)(fout);
if (din)
(void)fclose(din);
1993-03-21 12:45:37 +03:00
if (bytes > 0)
ptransfer(0);
(void)signal(SIGINT, oldintr);
(void)signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
}
/*
* Need to start a listen on the data channel before we send the command,
* otherwise the server's connect may fail.
*/
1994-08-25 07:47:50 +04:00
int
1993-03-21 12:45:37 +03:00
initconn()
{
1994-08-25 07:47:50 +04:00
char *p, *a;
1993-03-21 12:45:37 +03:00
int result, len, tmpno = 0;
int on = 1;
int a0, a1, a2, a3, p0, p1;
if (passivemode) {
data = socket(AF_INET, SOCK_STREAM, 0);
if (data < 0) {
warn("socket");
return (1);
}
if ((options & SO_DEBUG) &&
setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
sizeof(on)) < 0)
warn("setsockopt (ignored)");
if (command("PASV") != COMPLETE) {
puts("Passive mode refused.");
goto bad;
}
/*
* What we've got at this point is a string of comma
1995-09-08 05:05:59 +04:00
* separated one-byte unsigned integer values.
* The first four are the an IP address. The fifth is
* the MSB of the port number, the sixth is the LSB.
* From that we'll prepare a sockaddr_in.
*/
if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
&a0, &a1, &a2, &a3, &p0, &p1) != 6) {
puts(
"Passive mode address scan failure. Shouldn't happen!");
goto bad;
}
memset(&data_addr, 0, sizeof(data_addr));
data_addr.sin_family = AF_INET;
a = (char *)&data_addr.sin_addr.s_addr;
a[0] = a0 & 0xff;
a[1] = a1 & 0xff;
a[2] = a2 & 0xff;
a[3] = a3 & 0xff;
p = (char *)&data_addr.sin_port;
p[0] = p0 & 0xff;
p[1] = p1 & 0xff;
if (connect(data, (struct sockaddr *)&data_addr,
sizeof(data_addr)) < 0) {
warn("connect");
goto bad;
}
#ifdef IP_TOS
on = IPTOS_THROUGHPUT;
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
#endif
return (0);
}
1993-03-21 12:45:37 +03:00
noport:
data_addr = myctladdr;
if (sendport)
data_addr.sin_port = 0; /* let system pick one */
1993-03-21 12:45:37 +03:00
if (data != -1)
(void)close(data);
1993-03-21 12:45:37 +03:00
data = socket(AF_INET, SOCK_STREAM, 0);
if (data < 0) {
1994-08-25 07:47:50 +04:00
warn("socket");
1993-03-21 12:45:37 +03:00
if (tmpno)
sendport = 1;
return (1);
}
if (!sendport)
if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
sizeof(on)) < 0) {
1994-08-25 07:47:50 +04:00
warn("setsockopt (reuse address)");
1993-03-21 12:45:37 +03:00
goto bad;
}
if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
1994-08-25 07:47:50 +04:00
warn("bind");
1993-03-21 12:45:37 +03:00
goto bad;
}
if (options & SO_DEBUG &&
setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
sizeof(on)) < 0)
1994-08-25 07:47:50 +04:00
warn("setsockopt (ignored)");
len = sizeof(data_addr);
1993-03-21 12:45:37 +03:00
if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1994-08-25 07:47:50 +04:00
warn("getsockname");
1993-03-21 12:45:37 +03:00
goto bad;
}
if (listen(data, 1) < 0)
1994-08-25 07:47:50 +04:00
warn("listen");
1993-03-21 12:45:37 +03:00
if (sendport) {
a = (char *)&data_addr.sin_addr;
p = (char *)&data_addr.sin_port;
#define UC(b) (((int)b)&0xff)
result =
command("PORT %d,%d,%d,%d,%d,%d",
UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
UC(p[0]), UC(p[1]));
if (result == ERROR && sendport == -1) {
sendport = 0;
tmpno = 1;
goto noport;
}
return (result != COMPLETE);
}
if (tmpno)
sendport = 1;
#ifdef IP_TOS
on = IPTOS_THROUGHPUT;
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1994-08-25 07:47:50 +04:00
warn("setsockopt TOS (ignored)");
1993-03-21 12:45:37 +03:00
#endif
return (0);
bad:
(void)close(data), data = -1;
1993-03-21 12:45:37 +03:00
if (tmpno)
sendport = 1;
return (1);
}
FILE *
dataconn(lmode)
const char *lmode;
1993-03-21 12:45:37 +03:00
{
struct sockaddr_in from;
int s, fromlen, tos;
fromlen = sizeof(from);
1993-03-21 12:45:37 +03:00
if (passivemode)
return (fdopen(data, lmode));
1993-03-21 12:45:37 +03:00
s = accept(data, (struct sockaddr *) &from, &fromlen);
if (s < 0) {
1994-08-25 07:47:50 +04:00
warn("accept");
(void)close(data), data = -1;
1993-03-21 12:45:37 +03:00
return (NULL);
}
(void)close(data);
1993-03-21 12:45:37 +03:00
data = s;
#ifdef IP_TOS
tos = IPTOS_THROUGHPUT;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1994-08-25 07:47:50 +04:00
warn("setsockopt TOS (ignored)");
1993-03-21 12:45:37 +03:00
#endif
return (fdopen(data, lmode));
}
void
psummary(notused)
int notused;
{
if (bytes > 0)
ptransfer(1);
}
1993-03-21 12:45:37 +03:00
void
psabort(notused)
int notused;
1993-03-21 12:45:37 +03:00
{
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
alarmtimer(0);
1993-03-21 12:45:37 +03:00
abrtflag++;
}
1994-08-25 07:47:50 +04:00
void
1993-03-21 12:45:37 +03:00
pswitch(flag)
int flag;
{
sig_t oldintr;
static struct comvars {
int connect;
char name[MAXHOSTNAMELEN];
struct sockaddr_in mctl;
struct sockaddr_in hctl;
FILE *in;
FILE *out;
int tpe;
int curtpe;
int cpnd;
int sunqe;
int runqe;
int mcse;
int ntflg;
char nti[17];
char nto[17];
int mapflg;
char mi[MAXPATHLEN];
char mo[MAXPATHLEN];
} proxstruct, tmpstruct;
struct comvars *ip, *op;
abrtflag = 0;
oldintr = signal(SIGINT, psabort);
if (flag) {
if (proxy)
return;
ip = &tmpstruct;
op = &proxstruct;
proxy++;
} else {
if (!proxy)
return;
ip = &proxstruct;
op = &tmpstruct;
proxy = 0;
}
ip->connect = connected;
connected = op->connect;
if (hostname) {
(void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
ip->name[sizeof(ip->name) - 1] = '\0';
1993-03-21 12:45:37 +03:00
} else
ip->name[0] = '\0';
1993-03-21 12:45:37 +03:00
hostname = op->name;
ip->hctl = hisctladdr;
hisctladdr = op->hctl;
ip->mctl = myctladdr;
myctladdr = op->mctl;
ip->in = cin;
cin = op->in;
ip->out = cout;
cout = op->out;
ip->tpe = type;
type = op->tpe;
ip->curtpe = curtype;
curtype = op->curtpe;
ip->cpnd = cpend;
cpend = op->cpnd;
ip->sunqe = sunique;
sunique = op->sunqe;
ip->runqe = runique;
runique = op->runqe;
ip->mcse = mcase;
mcase = op->mcse;
ip->ntflg = ntflag;
ntflag = op->ntflg;
(void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
(ip->nti)[sizeof(ip->nti) - 1] = '\0';
(void)strcpy(ntin, op->nti);
(void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
(ip->nto)[sizeof(ip->nto) - 1] = '\0';
(void)strcpy(ntout, op->nto);
1993-03-21 12:45:37 +03:00
ip->mapflg = mapflag;
mapflag = op->mapflg;
(void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
(ip->mi)[sizeof(ip->mi) - 1] = '\0';
(void)strcpy(mapin, op->mi);
(void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
(ip->mo)[sizeof(ip->mo) - 1] = '\0';
(void)strcpy(mapout, op->mo);
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
if (abrtflag) {
abrtflag = 0;
(*oldintr)(SIGINT);
}
}
void
abortpt(notused)
int notused;
1993-03-21 12:45:37 +03:00
{
1994-08-25 07:47:50 +04:00
[Yet Another Huge Ftp Commit - hopefully the last for a while, barring any more little things people want added ...] New features: * progressmeter is now asynchronous, so "stalled" transfers can be detected. "- stalled -" is displayed instead of the ETA in this case. When the xfer resumes, the time that the xfer was stalled for is factored out of the ETA. It is debatable whether this is better than not factoring it out, but I like it this way (I.e, if it stalls for 8 seconds and the ETA was 30 seconds, when it resumes the ETA will still be 30 seconds). * verbosity can be disabled on the command line (-V), so that in auto-fetch mode the only lines displayed will be a description of the file, and the progress bar (if possible) * if the screen is resized (and detected via the SIGWINCH signal), the progress bar will rescale automatically. Bugs fixed: * progress bar will not use the last character on the line, as this can cause problems on some terminals * screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin * progressmeter() used some vars before initialising them * ^D will quit now. [fixes bin/3162] * use hstrerror() to generate error message for host name lookup failure. * use getcwd instead of getwd (it should have been OK, but why tempt fate?) * auto-fetch transfers will always return a positive exit value upon failure or interruption, relative to the file's position in argv[]. * remote completion of / will work, without putting a leading "///". This is actually a bug in ftpd(1), where "NLST /" prefixes all names with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
alarmtimer(0);
putchar('\n');
(void)fflush(stdout);
1993-03-21 12:45:37 +03:00
ptabflg++;
mflag = 0;
abrtflag = 0;
longjmp(ptabort, 1);
}
1994-08-25 07:47:50 +04:00
void
1993-03-21 12:45:37 +03:00
proxtrans(cmd, local, remote)
const char *cmd, *local, *remote;
1993-03-21 12:45:37 +03:00
{
sig_t oldintr;
int prox_type, nfnd;
volatile int secndflag;
1993-03-21 12:45:37 +03:00
char *cmd2;
struct fd_set mask;
#ifdef __GNUC__ /* XXX: to shut up gcc warnings */
(void)&oldintr;
(void)&cmd2;
#endif
oldintr = NULL;
secndflag = 0;
1993-03-21 12:45:37 +03:00
if (strcmp(cmd, "RETR"))
cmd2 = "RETR";
else
cmd2 = runique ? "STOU" : "STOR";
if ((prox_type = type) == 0) {
if (unix_server && unix_proxy)
prox_type = TYPE_I;
else
prox_type = TYPE_A;
}
if (curtype != prox_type)
changetype(prox_type, 1);
if (command("PASV") != COMPLETE) {
puts("proxy server does not support third party transfers.");
1993-03-21 12:45:37 +03:00
return;
}
pswitch(0);
if (!connected) {
puts("No primary connection.");
1993-03-21 12:45:37 +03:00
pswitch(1);
code = -1;
return;
}
if (curtype != prox_type)
changetype(prox_type, 1);
if (command("PORT %s", pasv) != COMPLETE) {
pswitch(1);
return;
}
if (setjmp(ptabort))
goto abort;
oldintr = signal(SIGINT, abortpt);
if (command("%s %s", cmd, remote) != PRELIM) {
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
pswitch(1);
return;
}
sleep(2);
pswitch(1);
secndflag++;
if (command("%s %s", cmd2, local) != PRELIM)
goto abort;
ptflag++;
(void)getreply(0);
1993-03-21 12:45:37 +03:00
pswitch(0);
(void)getreply(0);
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
pswitch(1);
ptflag = 0;
printf("local: %s remote: %s\n", local, remote);
return;
abort:
(void)signal(SIGINT, SIG_IGN);
1993-03-21 12:45:37 +03:00
ptflag = 0;
if (strcmp(cmd, "RETR") && !proxy)
pswitch(1);
else if (!strcmp(cmd, "RETR") && proxy)
pswitch(0);
if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
if (command("%s %s", cmd2, local) != PRELIM) {
pswitch(0);
if (cpend)
abort_remote(NULL);
1993-03-21 12:45:37 +03:00
}
pswitch(1);
if (ptabflg)
code = -1;
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
return;
}
if (cpend)
abort_remote(NULL);
1993-03-21 12:45:37 +03:00
pswitch(!proxy);
if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
if (command("%s %s", cmd2, local) != PRELIM) {
pswitch(0);
if (cpend)
abort_remote(NULL);
1993-03-21 12:45:37 +03:00
pswitch(1);
if (ptabflg)
code = -1;
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
return;
}
}
if (cpend)
abort_remote(NULL);
1993-03-21 12:45:37 +03:00
pswitch(!proxy);
if (cpend) {
FD_ZERO(&mask);
FD_SET(fileno(cin), &mask);
if ((nfnd = empty(&mask, 10)) <= 0) {
if (nfnd < 0) {
1994-08-25 07:47:50 +04:00
warn("abort");
1993-03-21 12:45:37 +03:00
}
if (ptabflg)
code = -1;
lostpeer();
}
(void)getreply(0);
(void)getreply(0);
1993-03-21 12:45:37 +03:00
}
if (proxy)
pswitch(0);
pswitch(1);
if (ptabflg)
code = -1;
(void)signal(SIGINT, oldintr);
1993-03-21 12:45:37 +03:00
}
1994-08-25 07:47:50 +04:00
void
reset(argc, argv)
int argc;
char *argv[];
1993-03-21 12:45:37 +03:00
{
struct fd_set mask;
int nfnd = 1;
FD_ZERO(&mask);
while (nfnd > 0) {
FD_SET(fileno(cin), &mask);
if ((nfnd = empty(&mask, 0)) < 0) {
1994-08-25 07:47:50 +04:00
warn("reset");
1993-03-21 12:45:37 +03:00
code = -1;
lostpeer();
}
else if (nfnd) {
(void)getreply(0);
1993-03-21 12:45:37 +03:00
}
}
}
char *
gunique(local)
const char *local;
1993-03-21 12:45:37 +03:00
{
static char new[MAXPATHLEN];
1994-08-25 07:47:50 +04:00
char *cp = strrchr(local, '/');
1993-03-21 12:45:37 +03:00
int d, count=0;
char ext = '1';
if (cp)
*cp = '\0';
d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1993-03-21 12:45:37 +03:00
if (cp)
*cp = '/';
if (d < 0) {
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
return (NULL);
1993-03-21 12:45:37 +03:00
}
(void)strcpy(new, local);
1993-03-21 12:45:37 +03:00
cp = new + strlen(new);
*cp++ = '.';
while (!d) {
if (++count == 100) {
puts("runique: can't find unique file name.");
return (NULL);
1993-03-21 12:45:37 +03:00
}
*cp++ = ext;
*cp = '\0';
if (ext == '9')
ext = '0';
else
ext++;
if ((d = access(new, F_OK)) < 0)
1993-03-21 12:45:37 +03:00
break;
if (ext != '0')
cp--;
else if (*(cp - 2) == '.')
*(cp - 1) = '1';
else {
*(cp - 2) = *(cp - 2) + 1;
cp--;
}
}
1994-08-25 07:47:50 +04:00
return (new);
1993-03-21 12:45:37 +03:00
}
1994-08-25 07:47:50 +04:00
void
1993-03-21 12:45:37 +03:00
abort_remote(din)
1994-08-25 07:47:50 +04:00
FILE *din;
1993-03-21 12:45:37 +03:00
{
char buf[BUFSIZ];
int nfnd;
struct fd_set mask;
if (cout == NULL) {
warnx("Lost control connection for abort.");
if (ptabflg)
code = -1;
lostpeer();
return;
}
1993-03-21 12:45:37 +03:00
/*
* send IAC in urgent mode instead of DM because 4.3BSD places oob mark
* after urgent byte rather than before as is protocol now
*/
sprintf(buf, "%c%c%c", IAC, IP, IAC);
if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1994-08-25 07:47:50 +04:00
warn("abort");
fprintf(cout, "%cABOR\r\n", DM);
(void)fflush(cout);
1993-03-21 12:45:37 +03:00
FD_ZERO(&mask);
FD_SET(fileno(cin), &mask);
if (din) {
1993-03-21 12:45:37 +03:00
FD_SET(fileno(din), &mask);
}
if ((nfnd = empty(&mask, 10)) <= 0) {
if (nfnd < 0) {
1994-08-25 07:47:50 +04:00
warn("abort");
1993-03-21 12:45:37 +03:00
}
if (ptabflg)
code = -1;
lostpeer();
}
if (din && FD_ISSET(fileno(din), &mask)) {
while (read(fileno(din), buf, BUFSIZ) > 0)
/* LOOP */;
}
if (getreply(0) == ERROR && code == 552) {
/* 552 needed for nic style abort */
(void)getreply(0);
1993-03-21 12:45:37 +03:00
}
(void)getreply(0);
1993-03-21 12:45:37 +03:00
}