NetBSD/usr.bin/ftp/ftp.c

1606 lines
33 KiB
C
Raw Normal View History

[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
/* $NetBSD: ftp.c,v 1.22 1997/02/01 10:45:03 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.
*/
#ifndef lint
1995-09-08 05:05:59 +04:00
#if 0
static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
#else
[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
static char rcsid[] = "$NetBSD: ftp.c,v 1.22 1997/02/01 10:45:03 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>
1993-03-21 12:45:37 +03:00
#include <pwd.h>
1994-08-25 07:47:50 +04:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
1993-03-21 12:45:37 +03:00
#include <varargs.h>
#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;
off_t restart_point = 0;
FILE *cin, *cout;
char *
hookup(host, port)
const char *host;
1993-03-21 12:45:37 +03:00
int port;
{
1994-08-25 07:47:50 +04:00
struct hostent *hp = 0;
1993-03-21 12:45:37 +03:00
int s, len, tos;
static char hostnamebuf[MAXHOSTNAMELEN];
1993-03-21 12:45:37 +03:00
1994-08-25 07:47:50 +04:00
memset((char *)&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));
} 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;
1994-08-25 07:47:50 +04:00
return ((char *) 0);
1993-03-21 12:45:37 +03:00
}
hisctladdr.sin_family = hp->h_addrtype;
1995-09-08 05:05:59 +04:00
memmove((caddr_t)&hisctladdr.sin_addr,
hp->h_addr_list[0], hp->h_length);
1995-05-21 19:50:45 +04:00
memcpy(&hisctladdr.sin_addr, hp->h_addr, hp->h_length);
1993-03-21 12:45:37 +03:00
(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
}
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++;
1994-08-25 07:47:50 +04:00
memmove((caddr_t)&hisctladdr.sin_addr,
hp->h_addr_list[0], hp->h_length);
1993-03-21 12:45:37 +03:00
fprintf(stdout, "Trying %s...\n",
inet_ntoa(hisctladdr.sin_addr));
(void) close(s);
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);
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);
if (cout)
(void) fclose(cout);
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);
if (cout)
(void) fclose(cout);
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 ((char *)0);
}
1994-08-25 07:47:50 +04:00
int
1993-03-21 12:45:37 +03:00
login(host)
const char *host;
1993-03-21 12:45:37 +03:00
{
char tmp[80];
1994-08-25 07:47:50 +04:00
char *user, *pass, *acct;
char anonpass[MAXLOGNAME + MAXHOSTNAMELEN + 2]; /* "user@hostname\0" */
char hostname[MAXHOSTNAMELEN + 1];
1993-03-21 12:45:37 +03:00
int n, aflag = 0;
user = pass = acct = NULL;
1993-03-21 12:45:37 +03:00
if (ruserpass(host, &user, &pass, &acct) < 0) {
code = -1;
1994-08-25 07:47:50 +04:00
return (0);
1993-03-21 12:45:37 +03:00
}
/*
* Set up arguments for an anonymous FTP session, if necessary.
*/
if ((user == NULL || pass == NULL) && anonftp) {
memset(anonpass, 0, sizeof(anonpass));
memset(hostname, 0, sizeof(hostname));
/*
* Set up anonymous login password.
*/
user = getlogin();
gethostname(hostname, MAXHOSTNAMELEN);
#ifndef DONT_CHEAT_ANONPASS
/*
* Every anonymous FTP server I've encountered
* will accept the string "username@", and will
* append the hostname itself. We do this by default
* since many servers are picky about not having
* a FQDN in the anonymous password. - thorpej@netbsd.org
*/
snprintf(anonpass, sizeof(anonpass) - 1, "%s@",
user);
#else
snprintf(anonpass, sizeof(anonpass) - 1, "%s@%s",
user, hp->h_name);
#endif
pass = anonpass;
user = "anonymous";
}
1993-03-21 12:45:37 +03:00
while (user == NULL) {
char *myname = getlogin();
if (myname == NULL) {
struct passwd *pp = getpwuid(getuid());
if (pp != NULL)
myname = pp->pw_name;
}
if (myname)
printf("Name (%s:%s): ", host, myname);
else
printf("Name (%s): ", host);
(void) fgets(tmp, sizeof(tmp) - 1, stdin);
tmp[strlen(tmp) - 1] = '\0';
if (*tmp == '\0')
user = myname;
else
user = tmp;
}
n = command("USER %s", user);
if (n == CONTINUE) {
if (pass == NULL)
pass = getpass("Password:");
n = command("PASS %s", pass);
}
if (n == CONTINUE) {
aflag++;
acct = getpass("Account:");
n = command("ACCT %s", acct);
}
if (n != COMPLETE) {
1994-08-25 07:47:50 +04:00
warnx("Login failed.");
1993-03-21 12:45:37 +03:00
return (0);
}
if (!aflag && acct != NULL)
(void) command("ACCT %s", acct);
if (proxy)
1994-08-25 07:47:50 +04:00
return (1);
1993-03-21 12:45:37 +03:00
for (n = 0; n < macnum; ++n) {
if (!strcmp("init", macros[n].mac_name)) {
(void) strcpy(line, "$init");
makeargv();
domacro(margc, margv);
break;
}
}
return (1);
}
void
cmdabort()
{
[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
printf("\n");
(void) fflush(stdout);
abrtflag++;
if (ptflag)
longjmp(ptabort, 1);
1993-03-21 12:45:37 +03:00
}
/*VARARGS*/
1994-08-25 07:47:50 +04:00
int
1993-03-21 12:45:37 +03:00
command(va_alist)
va_dcl
{
va_list ap;
char *fmt;
int r;
sig_t oldintr;
abrtflag = 0;
if (debug) {
printf("---> ");
va_start(ap);
fmt = va_arg(ap, char *);
if (strncmp("PASS ", fmt, 5) == 0)
printf("PASS XXXX");
else if (strncmp("ACCT ", fmt, 5) == 0)
printf("ACCT XXXX");
else
1993-03-21 12:45:37 +03:00
vfprintf(stdout, fmt, ap);
va_end(ap);
printf("\n");
(void) fflush(stdout);
}
if (cout == NULL) {
1994-08-25 07:47:50 +04:00
warn("No control connection for command");
1993-03-21 12:45:37 +03:00
code = -1;
return (0);
}
oldintr = signal(SIGINT, cmdabort);
va_start(ap);
fmt = va_arg(ap, char *);
vfprintf(cout, fmt, ap);
va_end(ap);
fprintf(cout, "\r\n");
(void) fflush(cout);
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);
break;
case DO:
case DONT:
c = getc(cin);
fprintf(cout, "%c%c%c", IAC, WONT, c);
(void) fflush(cout);
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) {
printf("421 Service not available, "
"remote server has closed "
"connection\n");
1993-03-21 12:45:37 +03:00
(void) fflush(stdout);
}
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);
1993-03-21 12:45:37 +03:00
(void) putchar(c);
}
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')) {
1993-03-21 12:45:37 +03:00
(void) putchar(c);
(void) fflush (stdout);
}
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;
1994-08-25 07:47:50 +04:00
return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
1993-03-21 12:45:37 +03:00
}
jmp_buf sendabort;
void
abortsend()
{
[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;
printf("\nsend aborted\nwaiting for remote to finish abort\n");
(void) fflush(stdout);
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 = 0;
1994-08-25 07:47:50 +04:00
int (*closefunc) __P((FILE *));
sig_t oldinti, oldintr, oldintp;
off_t hashbytes;
1993-03-21 12:45:37 +03:00
char *lmode, buf[BUFSIZ], *bufp;
hashbytes = mark;
direction = "sent";
bytes = 0;
filesize = -1;
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);
}
if (data >= 0) {
(void) close(data);
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;
return;
}
oldintr = signal(SIGINT, abortsend);
oldinti = signal(SIGINFO, psummary);
1993-03-21 12:45:37 +03:00
if (strcmp(local, "-") == 0)
fin = stdin;
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);
1993-03-21 12:45:37 +03:00
(void) signal(SIGINT, oldintr);
(void) signal(SIGPIPE, oldintp);
(void) signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
closefunc = pclose;
} else {
fin = fopen(local, "r");
if (fin == NULL) {
1994-08-25 07:47:50 +04:00
warn("local: %s", local);
1993-03-21 12:45:37 +03:00
(void) signal(SIGINT, oldintr);
(void) signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
closefunc = fclose;
if (fstat(fileno(fin), &st) < 0 ||
(st.st_mode&S_IFMT) != S_IFREG) {
fprintf(stdout, "%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;
return;
}
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);
code = -1;
if (closefunc != NULL)
(*closefunc)(fin);
return;
}
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
restart_point = 0;
if (closefunc != NULL)
(*closefunc)(fin);
return;
}
if (command("REST %ld", (long) restart_point)
!= CONTINUE) {
restart_point = 0;
if (closefunc != NULL)
(*closefunc)(fin);
return;
}
restart_point = 0;
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);
if (closefunc != NULL)
(*closefunc)(fin);
return;
}
} 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);
if (closefunc != NULL)
(*closefunc)(fin);
return;
}
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) {
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);
}
}
[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)
1993-03-21 12:45:37 +03:00
(void) putchar('#');
(void) putchar('\n');
(void) fflush(stdout);
}
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)) {
1993-03-21 12:45:37 +03:00
(void) putchar('#');
(void) fflush(stdout);
hashbytes += mark;
1993-03-21 12:45:37 +03:00
}
if (ferror(dout))
break;
(void) putc('\r', dout);
bytes++;
}
(void) putc(c, dout);
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);
}
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);
if (bytes > 0)
ptransfer(0);
1993-03-21 12:45:37 +03:00
return;
abort:
(void) signal(SIGINT, oldintr);
(void) signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
if (oldintp)
(void) signal(SIGPIPE, oldintp);
if (!cpend) {
code = -1;
return;
}
if (data >= 0) {
(void) close(data);
data = -1;
}
if (dout)
(void) fclose(dout);
(void) getreply(0);
code = -1;
if (closefunc != NULL && fin != NULL)
(*closefunc)(fin);
if (bytes > 0)
ptransfer(0);
1993-03-21 12:45:37 +03:00
}
jmp_buf recvabort;
void
abortrecv()
{
[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;
printf("\nreceive aborted\nwaiting for remote to finish abort\n");
(void) fflush(stdout);
longjmp(recvabort, 1);
}
1994-08-25 07:47:50 +04:00
void
1993-03-21 12:45:37 +03:00
recvrequest(cmd, local, remote, lmode, printnames)
const char *cmd, *local, *remote, *lmode;
1994-08-25 07:47:50 +04:00
int printnames;
1993-03-21 12:45:37 +03:00
{
1994-08-25 07:47:50 +04:00
FILE *fout, *din = 0;
int (*closefunc) __P((FILE *));
sig_t oldinti, oldintr, oldintp;
1994-08-25 07:47:50 +04:00
int c, d, is_retr, tcrflag, bare_lfs = 0;
1993-03-21 12:45:37 +03:00
static int bufsize;
static char *buf;
off_t hashbytes;
1993-03-21 12:45:37 +03:00
struct stat st;
time_t mtime;
struct timeval tval[2];
1993-03-21 12:45:37 +03:00
hashbytes = mark;
direction = "received";
bytes = 0;
filesize = -1;
1993-03-21 12:45:37 +03:00
is_retr = strcmp(cmd, "RETR") == 0;
if (is_retr && verbose && printnames) {
if (local && *local != '-')
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);
}
if (data >= 0) {
(void) close(data);
data = -1;
}
if (oldintr)
(void) signal(SIGINT, oldintr);
if (oldinti)
(void) signal(SIGINFO, oldinti);
1993-03-21 12:45:37 +03:00
code = -1;
return;
}
oldintr = signal(SIGINT, abortrecv);
oldinti = signal(SIGINFO, psummary);
1993-03-21 12:45:37 +03:00
if (strcmp(local, "-") && *local != '|') {
if (access(local, 2) < 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);
1993-03-21 12:45:37 +03:00
(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 : ".", 2);
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);
1993-03-21 12:45:37 +03:00
(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);
1993-03-21 12:45:37 +03:00
(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 %ld", (long) restart_point) != CONTINUE)
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 (strcmp(local, "-") == 0)
fout = stdout;
else if (*local == '|') {
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;
}
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);
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;
}
progressmeter(-1);
1993-03-21 12:45:37 +03:00
switch (curtype) {
case TYPE_I:
case TYPE_L:
1994-03-28 11:11:18 +04:00
if (restart_point &&
1994-08-25 07:47:50 +04:00
lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
warn("local: %s", local);
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);
}
}
[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)
1993-03-21 12:45:37 +03:00
(void) putchar('#');
(void) putchar('\n');
(void) fflush(stdout);
}
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 (restart_point) {
1994-08-25 07:47:50 +04:00
int i, n, ch;
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 = restart_point;
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);
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)) {
1993-03-21 12:45:37 +03:00
(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);
if (c == '\0') {
bytes++;
goto contin2;
}
if (c == EOF)
goto contin2;
}
}
(void) putc(c, fout);
bytes++;
contin2: ;
}
break2:
if (bare_lfs) {
printf("WARNING! %d bare linefeeds received in ASCII "
"mode\n", bare_lfs);
1993-03-21 12:45:37 +03:00
printf("File may not have transferred correctly.\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
if (hash && (!progress || filesize < 0)) {
1993-03-21 12:45:37 +03:00
if (bytes < hashbytes)
(void) putchar('#');
(void) putchar('\n');
(void) fflush(stdout);
}
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);
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],
(struct timezone *)0);
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;
abort:
/* abort using RFC959 recommended IP,SYNC sequence */
1993-03-21 12:45:37 +03:00
if (oldintp)
(void) signal(SIGPIPE, oldintp);
1993-03-21 12:45:37 +03:00
(void) signal(SIGINT, SIG_IGN);
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);
data = -1;
}
if (closefunc != NULL && fout != NULL)
(*closefunc)(fout);
if (din)
(void) fclose(din);
if (bytes > 0)
ptransfer(0);
1993-03-21 12:45:37 +03:00
(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) {
printf("Passive mode refused.\n");
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) {
printf("Passive mode address scan failure. "
"Shouldn't happen!\n");
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);
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)");
1993-03-21 12:45:37 +03:00
len = sizeof (data_addr);
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;
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 = sizeof (from), tos;
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");
1993-03-21 12:45:37 +03:00
(void) close(data), data = -1;
return (NULL);
}
(void) close(data);
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()
{
[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[strlen(ip->name)] = '\0';
} else
ip->name[0] = 0;
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, 16);
(ip->nti)[strlen(ip->nti)] = '\0';
(void) strcpy(ntin, op->nti);
(void) strncpy(ip->nto, ntout, 16);
(ip->nto)[strlen(ip->nto)] = '\0';
(void) strcpy(ntout, op->nto);
ip->mapflg = mapflag;
mapflag = op->mapflg;
(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
(ip->mi)[strlen(ip->mi)] = '\0';
(void) strcpy(mapin, op->mi);
(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
(ip->mo)[strlen(ip->mo)] = '\0';
(void) strcpy(mapout, op->mo);
(void) signal(SIGINT, oldintr);
if (abrtflag) {
abrtflag = 0;
(*oldintr)(SIGINT);
}
}
void
abortpt()
{
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);
1993-03-21 12:45:37 +03:00
printf("\n");
(void) fflush(stdout);
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 secndflag = 0, prox_type, nfnd;
char *cmd2;
struct fd_set mask;
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) {
printf("proxy server does not support third party "
"transfers.\n");
1993-03-21 12:45:37 +03:00
return;
}
pswitch(0);
if (!connected) {
printf("No primary connection\n");
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);
pswitch(1);
return;
}
sleep(2);
pswitch(1);
secndflag++;
if (command("%s %s", cmd2, local) != PRELIM)
goto abort;
ptflag++;
(void) getreply(0);
pswitch(0);
(void) getreply(0);
(void) signal(SIGINT, oldintr);
pswitch(1);
ptflag = 0;
printf("local: %s remote: %s\n", local, remote);
return;
abort:
(void) signal(SIGINT, SIG_IGN);
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((FILE *) NULL);
}
pswitch(1);
if (ptabflg)
code = -1;
(void) signal(SIGINT, oldintr);
return;
}
if (cpend)
abort_remote((FILE *) NULL);
pswitch(!proxy);
if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
if (command("%s %s", cmd2, local) != PRELIM) {
pswitch(0);
if (cpend)
abort_remote((FILE *) NULL);
pswitch(1);
if (ptabflg)
code = -1;
(void) signal(SIGINT, oldintr);
return;
}
}
if (cpend)
abort_remote((FILE *) NULL);
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);
}
if (proxy)
pswitch(0);
pswitch(1);
if (ptabflg)
code = -1;
(void) signal(SIGINT, oldintr);
}
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);
}
}
}
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 : ".", 2);
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 ((char *) 0);
1993-03-21 12:45:37 +03:00
}
(void) strcpy(new, local);
cp = new + strlen(new);
*cp++ = '.';
while (!d) {
if (++count == 100) {
printf("runique: can't find unique file name.\n");
1994-08-25 07:47:50 +04:00
return ((char *) 0);
1993-03-21 12:45:37 +03:00
}
*cp++ = ext;
*cp = '\0';
if (ext == '9')
ext = '0';
else
ext++;
if ((d = access(new, 0)) < 0)
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;
/*
* 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);
1993-03-21 12:45:37 +03:00
(void) fflush(cout);
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);
}
(void) getreply(0);
}