xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 36940)
121739Sdist /*
226048Sminshall  * Copyright (c) 1985 Regents of the University of California.
333737Sbostic  * All rights reserved.
433737Sbostic  *
533737Sbostic  * Redistribution and use in source and binary forms are permitted
634901Sbostic  * provided that the above copyright notice and this paragraph are
734901Sbostic  * duplicated in all such forms and that any documentation,
834901Sbostic  * advertising materials, and other materials related to such
934901Sbostic  * distribution and use acknowledge that the software was developed
1034901Sbostic  * by the University of California, Berkeley.  The name of the
1134901Sbostic  * University may not be used to endorse or promote products derived
1234901Sbostic  * from this software without specific prior written permission.
1334901Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434901Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1536935Skarels  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621739Sdist  */
1721739Sdist 
1810296Ssam #ifndef lint
19*36940Skarels static char sccsid[] = "@(#)ftp.c	5.24 (Berkeley) 03/01/89";
2033737Sbostic #endif /* not lint */
2110296Ssam 
22*36940Skarels #include <sys/param.h>
2310296Ssam #include <sys/stat.h>
2410296Ssam #include <sys/ioctl.h>
2510296Ssam #include <sys/socket.h>
2613614Ssam #include <sys/time.h>
2736935Skarels #include <sys/file.h>
2810296Ssam 
2910296Ssam #include <netinet/in.h>
3012397Ssam #include <arpa/ftp.h>
3126048Sminshall #include <arpa/telnet.h>
3210296Ssam 
3310296Ssam #include <stdio.h>
3410296Ssam #include <signal.h>
3510296Ssam #include <errno.h>
3610296Ssam #include <netdb.h>
3726048Sminshall #include <fcntl.h>
3826048Sminshall #include <pwd.h>
3910296Ssam 
40*36940Skarels #include "ftp_var.h"
41*36940Skarels 
4210296Ssam struct	sockaddr_in hisctladdr;
4310296Ssam struct	sockaddr_in data_addr;
4410296Ssam int	data = -1;
4526048Sminshall int	abrtflag = 0;
4626048Sminshall int	ptflag = 0;
4710296Ssam int	connected;
4810296Ssam struct	sockaddr_in myctladdr;
4926496Sminshall uid_t	getuid();
5036935Skarels off_t	restart_point = 0;
5110296Ssam 
5210296Ssam FILE	*cin, *cout;
5310296Ssam FILE	*dataconn();
5410296Ssam 
5525904Skarels char *
5610296Ssam hookup(host, port)
5710296Ssam 	char *host;
5810296Ssam 	int port;
5910296Ssam {
6025904Skarels 	register struct hostent *hp = 0;
6127687Sminshall 	int s,len;
6225904Skarels 	static char hostnamebuf[80];
6310296Ssam 
6410296Ssam 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
6525904Skarels 	hisctladdr.sin_addr.s_addr = inet_addr(host);
6625904Skarels 	if (hisctladdr.sin_addr.s_addr != -1) {
6725904Skarels 		hisctladdr.sin_family = AF_INET;
68*36940Skarels 		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
69*36940Skarels 	} else {
7025100Sbloom 		hp = gethostbyname(host);
7125904Skarels 		if (hp == NULL) {
7235792Sbostic 			fprintf(stderr, "ftp: %s: ", host);
7335792Sbostic 			herror((char *)NULL);
7426048Sminshall 			code = -1;
7526048Sminshall 			return((char *) 0);
7625904Skarels 		}
7725904Skarels 		hisctladdr.sin_family = hp->h_addrtype;
7825904Skarels 		bcopy(hp->h_addr_list[0],
7925904Skarels 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
80*36940Skarels 		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
8110296Ssam 	}
8225904Skarels 	hostname = hostnamebuf;
8325904Skarels 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
8410296Ssam 	if (s < 0) {
8510296Ssam 		perror("ftp: socket");
8626048Sminshall 		code = -1;
8710296Ssam 		return (0);
8810296Ssam 	}
8910296Ssam 	hisctladdr.sin_port = port;
9026496Sminshall 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
9125904Skarels 		if (hp && hp->h_addr_list[1]) {
9225904Skarels 			int oerrno = errno;
9325904Skarels 
9425904Skarels 			fprintf(stderr, "ftp: connect to address %s: ",
9525904Skarels 				inet_ntoa(hisctladdr.sin_addr));
9625904Skarels 			errno = oerrno;
9726496Sminshall 			perror((char *) 0);
9825904Skarels 			hp->h_addr_list++;
9925904Skarels 			bcopy(hp->h_addr_list[0],
10026048Sminshall 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
10126496Sminshall 			fprintf(stdout, "Trying %s...\n",
10225904Skarels 				inet_ntoa(hisctladdr.sin_addr));
10326813Skarels 			(void) close(s);
10426813Skarels 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
10526813Skarels 			if (s < 0) {
10626813Skarels 				perror("ftp: socket");
10726813Skarels 				code = -1;
10826813Skarels 				return (0);
10926813Skarels 			}
11025904Skarels 			continue;
11125904Skarels 		}
11210296Ssam 		perror("ftp: connect");
11326048Sminshall 		code = -1;
11410296Ssam 		goto bad;
11510296Ssam 	}
11611627Ssam 	len = sizeof (myctladdr);
11711627Ssam 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
11811627Ssam 		perror("ftp: getsockname");
11926048Sminshall 		code = -1;
12010296Ssam 		goto bad;
12110296Ssam 	}
12210296Ssam 	cin = fdopen(s, "r");
12310296Ssam 	cout = fdopen(s, "w");
12411219Ssam 	if (cin == NULL || cout == NULL) {
12510296Ssam 		fprintf(stderr, "ftp: fdopen failed.\n");
12610296Ssam 		if (cin)
12726496Sminshall 			(void) fclose(cin);
12810296Ssam 		if (cout)
12926496Sminshall 			(void) fclose(cout);
13026048Sminshall 		code = -1;
13110296Ssam 		goto bad;
13210296Ssam 	}
13310296Ssam 	if (verbose)
13426067Sminshall 		printf("Connected to %s.\n", hostname);
13527687Sminshall 	if (getreply(0) > 2) { 	/* read startup message from server */
13626048Sminshall 		if (cin)
13726496Sminshall 			(void) fclose(cin);
13826048Sminshall 		if (cout)
13926496Sminshall 			(void) fclose(cout);
14026048Sminshall 		code = -1;
14126048Sminshall 		goto bad;
14226048Sminshall 	}
14327687Sminshall #ifdef SO_OOBINLINE
14427687Sminshall 	{
14527687Sminshall 	int on = 1;
14626048Sminshall 
14727687Sminshall 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
14827687Sminshall 		< 0 && debug) {
14927687Sminshall 			perror("ftp: setsockopt");
15027687Sminshall 		}
15127687Sminshall 	}
15227687Sminshall #endif SO_OOBINLINE
15326048Sminshall 
15425904Skarels 	return (hostname);
15510296Ssam bad:
15626496Sminshall 	(void) close(s);
15725904Skarels 	return ((char *)0);
15810296Ssam }
15910296Ssam 
16025904Skarels login(host)
16125904Skarels 	char *host;
16210296Ssam {
16326048Sminshall 	char tmp[80];
16435659Sbostic 	char *user, *pass, *acct, *getlogin(), *getpass();
16526048Sminshall 	int n, aflag = 0;
16610296Ssam 
16726048Sminshall 	user = pass = acct = 0;
16826048Sminshall 	if (ruserpass(host, &user, &pass, &acct) < 0) {
16926048Sminshall 		code = -1;
17026048Sminshall 		return(0);
17126048Sminshall 	}
17226048Sminshall 	if (user == NULL) {
17326048Sminshall 		char *myname = getlogin();
17426048Sminshall 
17526048Sminshall 		if (myname == NULL) {
17626048Sminshall 			struct passwd *pp = getpwuid(getuid());
17726048Sminshall 
17826448Slepreau 			if (pp != NULL)
17926048Sminshall 				myname = pp->pw_name;
18026048Sminshall 		}
18126048Sminshall 		printf("Name (%s:%s): ", host, myname);
18226048Sminshall 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
18326048Sminshall 		tmp[strlen(tmp) - 1] = '\0';
18426448Slepreau 		if (*tmp == '\0')
18526048Sminshall 			user = myname;
18626448Slepreau 		else
18726048Sminshall 			user = tmp;
18826048Sminshall 	}
18910296Ssam 	n = command("USER %s", user);
19026048Sminshall 	if (n == CONTINUE) {
19126448Slepreau 		if (pass == NULL)
19235659Sbostic 			pass = getpass("Password:");
19310296Ssam 		n = command("PASS %s", pass);
19426048Sminshall 	}
19510296Ssam 	if (n == CONTINUE) {
19626048Sminshall 		aflag++;
19735659Sbostic 		acct = getpass("Account:");
19810296Ssam 		n = command("ACCT %s", acct);
19910296Ssam 	}
20010296Ssam 	if (n != COMPLETE) {
20110296Ssam 		fprintf(stderr, "Login failed.\n");
20210296Ssam 		return (0);
20310296Ssam 	}
20426448Slepreau 	if (!aflag && acct != NULL)
20526048Sminshall 		(void) command("ACCT %s", acct);
20626448Slepreau 	if (proxy)
20726048Sminshall 		return(1);
20826048Sminshall 	for (n = 0; n < macnum; ++n) {
20926048Sminshall 		if (!strcmp("init", macros[n].mac_name)) {
21026496Sminshall 			(void) strcpy(line, "$init");
21126048Sminshall 			makeargv();
21226048Sminshall 			domacro(margc, margv);
21326048Sminshall 			break;
21426048Sminshall 		}
21526048Sminshall 	}
21610296Ssam 	return (1);
21710296Ssam }
21810296Ssam 
21926048Sminshall cmdabort()
22026048Sminshall {
22126048Sminshall 	extern jmp_buf ptabort;
22226048Sminshall 
22326048Sminshall 	printf("\n");
22426048Sminshall 	(void) fflush(stdout);
22526048Sminshall 	abrtflag++;
22626448Slepreau 	if (ptflag)
22726048Sminshall 		longjmp(ptabort,1);
22826048Sminshall }
22926048Sminshall 
23026496Sminshall /*VARARGS1*/
23110296Ssam command(fmt, args)
23210296Ssam 	char *fmt;
23310296Ssam {
23426048Sminshall 	int r, (*oldintr)(), cmdabort();
23510296Ssam 
23626048Sminshall 	abrtflag = 0;
23710296Ssam 	if (debug) {
23810296Ssam 		printf("---> ");
23910296Ssam 		_doprnt(fmt, &args, stdout);
24010296Ssam 		printf("\n");
24110296Ssam 		(void) fflush(stdout);
24210296Ssam 	}
24311219Ssam 	if (cout == NULL) {
24411219Ssam 		perror ("No control connection for command");
24526048Sminshall 		code = -1;
24611219Ssam 		return (0);
24711219Ssam 	}
24826048Sminshall 	oldintr = signal(SIGINT,cmdabort);
24910296Ssam 	_doprnt(fmt, &args, cout);
25010296Ssam 	fprintf(cout, "\r\n");
25110296Ssam 	(void) fflush(cout);
25226048Sminshall 	cpend = 1;
25326048Sminshall 	r = getreply(!strcmp(fmt, "QUIT"));
25426448Slepreau 	if (abrtflag && oldintr != SIG_IGN)
25526048Sminshall 		(*oldintr)();
25626048Sminshall 	(void) signal(SIGINT, oldintr);
25726048Sminshall 	return(r);
25810296Ssam }
25910296Ssam 
26036935Skarels char reply_string[BUFSIZ];
26136935Skarels 
26210296Ssam #include <ctype.h>
26310296Ssam 
26410296Ssam getreply(expecteof)
26510296Ssam 	int expecteof;
26610296Ssam {
26711219Ssam 	register int c, n;
26826048Sminshall 	register int dig;
26936935Skarels 	register char *cp;
27026048Sminshall 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
27126048Sminshall 	int pflag = 0;
27226048Sminshall 	char *pt = pasv;
27310296Ssam 
27436935Skarels 	cp = reply_string;
27526048Sminshall 	oldintr = signal(SIGINT,cmdabort);
27610296Ssam 	for (;;) {
27710296Ssam 		dig = n = code = 0;
27810296Ssam 		while ((c = getc(cin)) != '\n') {
27927687Sminshall 			if (c == IAC) {     /* handle telnet commands */
28027687Sminshall 				switch (c = getc(cin)) {
28127687Sminshall 				case WILL:
28227687Sminshall 				case WONT:
28327687Sminshall 					c = getc(cin);
284*36940Skarels 					fprintf(cout, "%c%c%c",IAC,DONT,c);
28527687Sminshall 					(void) fflush(cout);
28627687Sminshall 					break;
28727687Sminshall 				case DO:
28827687Sminshall 				case DONT:
28927687Sminshall 					c = getc(cin);
290*36940Skarels 					fprintf(cout, "%c%c%c",IAC,WONT,c);
29127687Sminshall 					(void) fflush(cout);
29227687Sminshall 					break;
29327687Sminshall 				default:
29427687Sminshall 					break;
29527687Sminshall 				}
29627687Sminshall 				continue;
29727687Sminshall 			}
29810296Ssam 			dig++;
29910296Ssam 			if (c == EOF) {
30026048Sminshall 				if (expecteof) {
30126048Sminshall 					(void) signal(SIGINT,oldintr);
30226048Sminshall 					code = 221;
30310296Ssam 					return (0);
30426048Sminshall 				}
30510296Ssam 				lostpeer();
30626048Sminshall 				if (verbose) {
30726048Sminshall 					printf("421 Service not available, remote server has closed connection\n");
30826048Sminshall 					(void) fflush(stdout);
30926048Sminshall 				}
31033772Scsvsj 				code = 421;
31133772Scsvsj 				return(4);
31210296Ssam 			}
31326048Sminshall 			if (c != '\r' && (verbose > 0 ||
31426048Sminshall 			    (verbose > -1 && n == '5' && dig > 4))) {
31526448Slepreau 				if (proxflag &&
31626448Slepreau 				   (dig == 1 || dig == 5 && verbose == 0))
31726048Sminshall 					printf("%s:",hostname);
31826496Sminshall 				(void) putchar(c);
31926048Sminshall 			}
32010296Ssam 			if (dig < 4 && isdigit(c))
32110296Ssam 				code = code * 10 + (c - '0');
32226448Slepreau 			if (!pflag && code == 227)
32326048Sminshall 				pflag = 1;
32426448Slepreau 			if (dig > 4 && pflag == 1 && isdigit(c))
32526048Sminshall 				pflag = 2;
32626048Sminshall 			if (pflag == 2) {
32726448Slepreau 				if (c != '\r' && c != ')')
32826048Sminshall 					*pt++ = c;
32926048Sminshall 				else {
33026048Sminshall 					*pt = '\0';
33126048Sminshall 					pflag = 3;
33226048Sminshall 				}
33326048Sminshall 			}
33426048Sminshall 			if (dig == 4 && c == '-') {
33526448Slepreau 				if (continuation)
33626048Sminshall 					code = 0;
33710296Ssam 				continuation++;
33826048Sminshall 			}
33910296Ssam 			if (n == 0)
34010296Ssam 				n = c;
34136935Skarels 			*cp++ = c;
34210296Ssam 		}
34326048Sminshall 		if (verbose > 0 || verbose > -1 && n == '5') {
34426496Sminshall 			(void) putchar(c);
34511346Ssam 			(void) fflush (stdout);
34611346Ssam 		}
34710296Ssam 		if (continuation && code != originalcode) {
34810296Ssam 			if (originalcode == 0)
34910296Ssam 				originalcode = code;
35010296Ssam 			continue;
35110296Ssam 		}
35236935Skarels 		*cp = '\0';
35326448Slepreau 		if (n != '1')
35426048Sminshall 			cpend = 0;
35526048Sminshall 		(void) signal(SIGINT,oldintr);
35626448Slepreau 		if (code == 421 || originalcode == 421)
35726048Sminshall 			lostpeer();
35826448Slepreau 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
35926048Sminshall 			(*oldintr)();
36025907Smckusick 		return (n - '0');
36110296Ssam 	}
36210296Ssam }
36310296Ssam 
36426048Sminshall empty(mask, sec)
36527687Sminshall 	struct fd_set *mask;
36626048Sminshall 	int sec;
36726048Sminshall {
36826048Sminshall 	struct timeval t;
36926048Sminshall 
37026048Sminshall 	t.tv_sec = (long) sec;
37126048Sminshall 	t.tv_usec = 0;
37227687Sminshall 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
37326048Sminshall }
37426048Sminshall 
37510296Ssam jmp_buf	sendabort;
37610296Ssam 
37710296Ssam abortsend()
37810296Ssam {
37910296Ssam 
38026048Sminshall 	mflag = 0;
38126048Sminshall 	abrtflag = 0;
38226048Sminshall 	printf("\nsend aborted\n");
38326048Sminshall 	(void) fflush(stdout);
38410296Ssam 	longjmp(sendabort, 1);
38510296Ssam }
38610296Ssam 
387*36940Skarels #define HASHBYTES 1024
388*36940Skarels 
38910296Ssam sendrequest(cmd, local, remote)
39010296Ssam 	char *cmd, *local, *remote;
39110296Ssam {
39235659Sbostic 	FILE *fin, *dout = 0, *popen();
39335659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
39426048Sminshall 	int abortsend();
39511219Ssam 	char buf[BUFSIZ];
396*36940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
39711346Ssam 	register int c, d;
39810296Ssam 	struct stat st;
39910296Ssam 	struct timeval start, stop;
40036935Skarels 	char *mode;
40110296Ssam 
40226048Sminshall 	if (proxy) {
40326048Sminshall 		proxtrans(cmd, local, remote);
40426048Sminshall 		return;
40526048Sminshall 	}
40610296Ssam 	closefunc = NULL;
40726048Sminshall 	oldintr = NULL;
40826048Sminshall 	oldintp = NULL;
40936935Skarels 	mode = "w";
41026048Sminshall 	if (setjmp(sendabort)) {
41126048Sminshall 		while (cpend) {
41226048Sminshall 			(void) getreply(0);
41326048Sminshall 		}
41426048Sminshall 		if (data >= 0) {
41526048Sminshall 			(void) close(data);
41626048Sminshall 			data = -1;
41726048Sminshall 		}
41826448Slepreau 		if (oldintr)
41926048Sminshall 			(void) signal(SIGINT,oldintr);
42026448Slepreau 		if (oldintp)
42126048Sminshall 			(void) signal(SIGPIPE,oldintp);
42226048Sminshall 		code = -1;
42326048Sminshall 		return;
42426048Sminshall 	}
42510296Ssam 	oldintr = signal(SIGINT, abortsend);
42610296Ssam 	if (strcmp(local, "-") == 0)
42710296Ssam 		fin = stdin;
42810296Ssam 	else if (*local == '|') {
42926048Sminshall 		oldintp = signal(SIGPIPE,SIG_IGN);
43035659Sbostic 		fin = popen(local + 1, "r");
43110296Ssam 		if (fin == NULL) {
43226048Sminshall 			perror(local + 1);
43326048Sminshall 			(void) signal(SIGINT, oldintr);
43426048Sminshall 			(void) signal(SIGPIPE, oldintp);
43526048Sminshall 			code = -1;
43626048Sminshall 			return;
43710296Ssam 		}
43835659Sbostic 		closefunc = pclose;
43910296Ssam 	} else {
44010296Ssam 		fin = fopen(local, "r");
44110296Ssam 		if (fin == NULL) {
44210296Ssam 			perror(local);
44326048Sminshall 			(void) signal(SIGINT, oldintr);
44426048Sminshall 			code = -1;
44526048Sminshall 			return;
44610296Ssam 		}
44710296Ssam 		closefunc = fclose;
44810296Ssam 		if (fstat(fileno(fin), &st) < 0 ||
44910296Ssam 		    (st.st_mode&S_IFMT) != S_IFREG) {
45026496Sminshall 			fprintf(stdout, "%s: not a plain file.\n", local);
45126048Sminshall 			(void) signal(SIGINT, oldintr);
45236935Skarels 			fclose(fin);
45326048Sminshall 			code = -1;
45426048Sminshall 			return;
45510296Ssam 		}
45610296Ssam 	}
45726048Sminshall 	if (initconn()) {
45826048Sminshall 		(void) signal(SIGINT, oldintr);
45926448Slepreau 		if (oldintp)
46026048Sminshall 			(void) signal(SIGPIPE, oldintp);
46126048Sminshall 		code = -1;
46236935Skarels 		if (closefunc != NULL)
46336935Skarels 			(*closefunc)(fin);
46426048Sminshall 		return;
46526048Sminshall 	}
46626448Slepreau 	if (setjmp(sendabort))
46726048Sminshall 		goto abort;
46836935Skarels 
46936935Skarels 	if (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0) {
47036935Skarels 		if (restart_point) {
47136935Skarels 			if (fseek(fin, (long) restart_point, 0) < 0) {
47236935Skarels 				perror(local);
47336935Skarels 				restart_point = 0;
47436935Skarels 				if (closefunc != NULL)
47536935Skarels 					(*closefunc)(fin);
47636935Skarels 				return;
47736935Skarels 			}
47836935Skarels 			if (command("REST %ld", (long) restart_point)
47936935Skarels 				!= CONTINUE) {
48036935Skarels 				restart_point = 0;
48136935Skarels 				if (closefunc != NULL)
48236935Skarels 					(*closefunc)(fin);
48336935Skarels 				return;
48436935Skarels 			}
48536935Skarels 			restart_point = 0;
48636935Skarels 			mode = "r+w";
48736935Skarels 		}
48836935Skarels 	}
48910296Ssam 	if (remote) {
49026048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
49126048Sminshall 			(void) signal(SIGINT, oldintr);
49226448Slepreau 			if (oldintp)
49326048Sminshall 				(void) signal(SIGPIPE, oldintp);
49436935Skarels 			if (closefunc != NULL)
49536935Skarels 				(*closefunc)(fin);
49626048Sminshall 			return;
49726048Sminshall 		}
49810296Ssam 	} else
49926048Sminshall 		if (command("%s", cmd) != PRELIM) {
50026048Sminshall 			(void) signal(SIGINT, oldintr);
50126448Slepreau 			if (oldintp)
50226048Sminshall 				(void) signal(SIGPIPE, oldintp);
50336935Skarels 			if (closefunc != NULL)
50436935Skarels 				(*closefunc)(fin);
50526048Sminshall 			return;
50626048Sminshall 		}
50736935Skarels 	dout = dataconn(mode);
50826448Slepreau 	if (dout == NULL)
50926048Sminshall 		goto abort;
51026496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
51136935Skarels 	oldintp = signal(SIGPIPE, SIG_IGN);
51211219Ssam 	switch (type) {
51311219Ssam 
51411219Ssam 	case TYPE_I:
51511219Ssam 	case TYPE_L:
51611346Ssam 		errno = d = 0;
51711219Ssam 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
51836935Skarels 			if ((d = write(fileno (dout), buf, c)) != c)
51911219Ssam 				break;
52011219Ssam 			bytes += c;
52111651Ssam 			if (hash) {
522*36940Skarels 				while (bytes >= hashbytes) {
523*36940Skarels 					(void) putchar('#');
524*36940Skarels 					hashbytes += HASHBYTES;
525*36940Skarels 				}
52626496Sminshall 				(void) fflush(stdout);
52711651Ssam 			}
52811219Ssam 		}
52913213Ssam 		if (hash && bytes > 0) {
530*36940Skarels 			if (bytes < HASHBYTES)
531*36940Skarels 				(void) putchar('#');
53226496Sminshall 			(void) putchar('\n');
53326496Sminshall 			(void) fflush(stdout);
53411651Ssam 		}
53511219Ssam 		if (c < 0)
53611219Ssam 			perror(local);
53736935Skarels 		if (d < 0) {
53836935Skarels 			if (errno != EPIPE)
53936935Skarels 				perror("netout");
54036935Skarels 			bytes = -1;
54136935Skarels 		}
54211219Ssam 		break;
54311219Ssam 
54411219Ssam 	case TYPE_A:
54511219Ssam 		while ((c = getc(fin)) != EOF) {
54611219Ssam 			if (c == '\n') {
54711651Ssam 				while (hash && (bytes >= hashbytes)) {
54826496Sminshall 					(void) putchar('#');
54926496Sminshall 					(void) fflush(stdout);
550*36940Skarels 					hashbytes += HASHBYTES;
55111651Ssam 				}
55211219Ssam 				if (ferror(dout))
55311219Ssam 					break;
55426496Sminshall 				(void) putc('\r', dout);
55511219Ssam 				bytes++;
55611219Ssam 			}
55726496Sminshall 			(void) putc(c, dout);
55811219Ssam 			bytes++;
55926048Sminshall 	/*		if (c == '\r') {			  	*/
56026496Sminshall 	/*		(void)	putc('\0', dout);  /* this violates rfc */
56126048Sminshall 	/*			bytes++;				*/
56226048Sminshall 	/*		}                          			*/
56311219Ssam 		}
56411651Ssam 		if (hash) {
56513213Ssam 			if (bytes < hashbytes)
56626496Sminshall 				(void) putchar('#');
56726496Sminshall 			(void) putchar('\n');
56826496Sminshall 			(void) fflush(stdout);
56911651Ssam 		}
57011219Ssam 		if (ferror(fin))
57111219Ssam 			perror(local);
57236935Skarels 		if (ferror(dout)) {
57336935Skarels 			if (errno != EPIPE)
57436935Skarels 				perror("netout");
57536935Skarels 			bytes = -1;
57636935Skarels 		}
57711219Ssam 		break;
57810296Ssam 	}
57926496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
58010296Ssam 	if (closefunc != NULL)
58126048Sminshall 		(*closefunc)(fin);
58210296Ssam 	(void) fclose(dout);
58326048Sminshall 	(void) getreply(0);
58426048Sminshall 	(void) signal(SIGINT, oldintr);
58536935Skarels 	if (oldintp)
58636935Skarels 		(void) signal(SIGPIPE, oldintp);
58735699Sbostic 	if (bytes > 0)
58826048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
58910296Ssam 	return;
59026048Sminshall abort:
59126496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
59226048Sminshall 	(void) signal(SIGINT, oldintr);
59326448Slepreau 	if (oldintp)
59426048Sminshall 		(void) signal(SIGPIPE, oldintp);
59526048Sminshall 	if (!cpend) {
59626048Sminshall 		code = -1;
59726048Sminshall 		return;
59826048Sminshall 	}
59926048Sminshall 	if (data >= 0) {
60026048Sminshall 		(void) close(data);
60126048Sminshall 		data = -1;
60226048Sminshall 	}
60326448Slepreau 	if (dout)
60426048Sminshall 		(void) fclose(dout);
60526048Sminshall 	(void) getreply(0);
60626048Sminshall 	code = -1;
60710296Ssam 	if (closefunc != NULL && fin != NULL)
60826048Sminshall 		(*closefunc)(fin);
60935699Sbostic 	if (bytes > 0)
61026048Sminshall 		ptransfer("sent", bytes, &start, &stop, local, remote);
61110296Ssam }
61210296Ssam 
61310296Ssam jmp_buf	recvabort;
61410296Ssam 
61510296Ssam abortrecv()
61610296Ssam {
61710296Ssam 
61826048Sminshall 	mflag = 0;
61926048Sminshall 	abrtflag = 0;
62026048Sminshall 	printf("\n");
62126048Sminshall 	(void) fflush(stdout);
62210296Ssam 	longjmp(recvabort, 1);
62310296Ssam }
62410296Ssam 
62511651Ssam recvrequest(cmd, local, remote, mode)
62611651Ssam 	char *cmd, *local, *remote, *mode;
62710296Ssam {
62835659Sbostic 	FILE *fout, *din = 0, *popen();
62935659Sbostic 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
63036935Skarels 	int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd;
631*36940Skarels 	char *buf, *gunique(), msg;
632*36940Skarels 	static int bufsize;
633*36940Skarels 	long bytes = 0, hashbytes = HASHBYTES;
63426496Sminshall 	struct fd_set mask;
63511346Ssam 	register int c, d;
63610296Ssam 	struct timeval start, stop;
637*36940Skarels 	struct stat st;
638*36940Skarels 	extern char *malloc();
63910296Ssam 
64036935Skarels 	is_retr = strcmp(cmd, "RETR") == 0;
64136935Skarels 	if (proxy && is_retr) {
64226048Sminshall 		proxtrans(cmd, local, remote);
64326048Sminshall 		return;
64426048Sminshall 	}
64510296Ssam 	closefunc = NULL;
64626048Sminshall 	oldintr = NULL;
64726048Sminshall 	oldintp = NULL;
64836935Skarels 	tcrflag = !crflag && is_retr;
64926048Sminshall 	if (setjmp(recvabort)) {
65026048Sminshall 		while (cpend) {
65126048Sminshall 			(void) getreply(0);
65226048Sminshall 		}
65326048Sminshall 		if (data >= 0) {
65426048Sminshall 			(void) close(data);
65526048Sminshall 			data = -1;
65626048Sminshall 		}
65726448Slepreau 		if (oldintr)
65826048Sminshall 			(void) signal(SIGINT, oldintr);
65926048Sminshall 		code = -1;
66026048Sminshall 		return;
66126048Sminshall 	}
66210296Ssam 	oldintr = signal(SIGINT, abortrecv);
66326048Sminshall 	if (strcmp(local, "-") && *local != '|') {
66410296Ssam 		if (access(local, 2) < 0) {
66526048Sminshall 			char *dir = rindex(local, '/');
66610296Ssam 
66726048Sminshall 			if (errno != ENOENT && errno != EACCES) {
66810296Ssam 				perror(local);
66926048Sminshall 				(void) signal(SIGINT, oldintr);
67026048Sminshall 				code = -1;
67126048Sminshall 				return;
67210296Ssam 			}
67326048Sminshall 			if (dir != NULL)
67426048Sminshall 				*dir = 0;
67526048Sminshall 			d = access(dir ? local : ".", 2);
67626048Sminshall 			if (dir != NULL)
67726048Sminshall 				*dir = '/';
67826048Sminshall 			if (d < 0) {
67926048Sminshall 				perror(local);
68026048Sminshall 				(void) signal(SIGINT, oldintr);
68126048Sminshall 				code = -1;
68226048Sminshall 				return;
68326048Sminshall 			}
68426048Sminshall 			if (!runique && errno == EACCES &&
68536935Skarels 			    chmod(local, 0600) < 0) {
68626048Sminshall 				perror(local);
68726048Sminshall 				(void) signal(SIGINT, oldintr);
68826048Sminshall 				code = -1;
68926048Sminshall 				return;
69026048Sminshall 			}
69126048Sminshall 			if (runique && errno == EACCES &&
69226048Sminshall 			   (local = gunique(local)) == NULL) {
69326048Sminshall 				(void) signal(SIGINT, oldintr);
69426048Sminshall 				code = -1;
69526048Sminshall 				return;
69626048Sminshall 			}
69710296Ssam 		}
69826048Sminshall 		else if (runique && (local = gunique(local)) == NULL) {
69926048Sminshall 			(void) signal(SIGINT, oldintr);
70026048Sminshall 			code = -1;
70126048Sminshall 			return;
70226048Sminshall 		}
70326048Sminshall 	}
70426048Sminshall 	if (initconn()) {
70526048Sminshall 		(void) signal(SIGINT, oldintr);
70626048Sminshall 		code = -1;
70726048Sminshall 		return;
70826048Sminshall 	}
70926448Slepreau 	if (setjmp(recvabort))
71026048Sminshall 		goto abort;
71136935Skarels 	if (!is_retr) {
71236935Skarels 		if (type != TYPE_A) {
71336935Skarels 			oldtype = type;
71436935Skarels 			oldverbose = verbose;
71536935Skarels 			if (!debug)
71636935Skarels 				verbose = 0;
71736935Skarels 			setascii();
71836935Skarels 			verbose = oldverbose;
71936935Skarels 		}
72036935Skarels 	} else if (restart_point) {
72136935Skarels 		if (command("REST %ld", (long) restart_point) != CONTINUE)
72236935Skarels 			return;
72326048Sminshall 	}
72410296Ssam 	if (remote) {
72526048Sminshall 		if (command("%s %s", cmd, remote) != PRELIM) {
72626048Sminshall 			(void) signal(SIGINT, oldintr);
72726048Sminshall 			if (oldtype) {
72826448Slepreau 				if (!debug)
72926048Sminshall 					verbose = 0;
73026048Sminshall 				switch (oldtype) {
73126048Sminshall 					case TYPE_I:
73226048Sminshall 						setbinary();
73326048Sminshall 						break;
73426048Sminshall 					case TYPE_E:
73526048Sminshall 						setebcdic();
73626048Sminshall 						break;
73726048Sminshall 					case TYPE_L:
73826048Sminshall 						settenex();
73926048Sminshall 						break;
74036935Skarels 					}
74126048Sminshall 				verbose = oldverbose;
74226048Sminshall 			}
74326048Sminshall 			return;
74426048Sminshall 		}
74526048Sminshall 	} else {
74626048Sminshall 		if (command("%s", cmd) != PRELIM) {
74726048Sminshall 			(void) signal(SIGINT, oldintr);
74826048Sminshall 			if (oldtype) {
74926448Slepreau 				if (!debug)
75026048Sminshall 					verbose = 0;
75126048Sminshall 				switch (oldtype) {
75226048Sminshall 					case TYPE_I:
75326048Sminshall 						setbinary();
75426048Sminshall 						break;
75526048Sminshall 					case TYPE_E:
75626048Sminshall 						setebcdic();
75726048Sminshall 						break;
75826048Sminshall 					case TYPE_L:
75926048Sminshall 						settenex();
76026048Sminshall 						break;
76136935Skarels 					}
76226048Sminshall 				verbose = oldverbose;
76326048Sminshall 			}
76426048Sminshall 			return;
76526048Sminshall 		}
76626048Sminshall 	}
76726048Sminshall 	din = dataconn("r");
76826048Sminshall 	if (din == NULL)
76926048Sminshall 		goto abort;
77026448Slepreau 	if (strcmp(local, "-") == 0)
77110296Ssam 		fout = stdout;
77210296Ssam 	else if (*local == '|') {
77326048Sminshall 		oldintp = signal(SIGPIPE, SIG_IGN);
77435659Sbostic 		fout = popen(local + 1, "w");
77526048Sminshall 		if (fout == NULL) {
77626048Sminshall 			perror(local+1);
77726048Sminshall 			goto abort;
77826048Sminshall 		}
77935659Sbostic 		closefunc = pclose;
780*36940Skarels 	} else {
78111651Ssam 		fout = fopen(local, mode);
78226048Sminshall 		if (fout == NULL) {
78326048Sminshall 			perror(local);
78426048Sminshall 			goto abort;
78526048Sminshall 		}
78610296Ssam 		closefunc = fclose;
78710296Ssam 	}
788*36940Skarels 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
789*36940Skarels 		st.st_blksize = BUFSIZ;
790*36940Skarels 	if (st.st_blksize > bufsize) {
791*36940Skarels 		if (buf)
792*36940Skarels 			(void) free(buf);
793*36940Skarels 		buf = malloc(st.st_blksize);
794*36940Skarels 		if (buf == NULL) {
795*36940Skarels 			perror("malloc");
796*36940Skarels 			goto abort;
797*36940Skarels 		}
798*36940Skarels 		bufsize = st.st_blksize;
799*36940Skarels 	}
80026496Sminshall 	(void) gettimeofday(&start, (struct timezone *)0);
80111219Ssam 	switch (type) {
80211219Ssam 
80311219Ssam 	case TYPE_I:
80411219Ssam 	case TYPE_L:
80536935Skarels 		if (restart_point &&
80636935Skarels 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
80736935Skarels 			perror(local);
80836935Skarels 			if (closefunc != NULL)
80936935Skarels 				(*closefunc)(fout);
81036935Skarels 			return;
81136935Skarels 		}
81211346Ssam 		errno = d = 0;
813*36940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
81436935Skarels 			if ((d = write(fileno(fout), buf, c)) != c)
81511219Ssam 				break;
81611219Ssam 			bytes += c;
81711651Ssam 			if (hash) {
818*36940Skarels 				while (bytes >= hashbytes) {
819*36940Skarels 					(void) putchar('#');
820*36940Skarels 					hashbytes += HASHBYTES;
821*36940Skarels 				}
82226496Sminshall 				(void) fflush(stdout);
82311651Ssam 			}
82411219Ssam 		}
82513213Ssam 		if (hash && bytes > 0) {
826*36940Skarels 			if (bytes < HASHBYTES)
827*36940Skarels 				(void) putchar('#');
82826496Sminshall 			(void) putchar('\n');
82926496Sminshall 			(void) fflush(stdout);
83011651Ssam 		}
83136935Skarels 		if (c < 0) {
83236935Skarels 			if (errno != EPIPE)
83336935Skarels 				perror("netin");
83436935Skarels 			bytes = -1;
83536935Skarels 		}
83611346Ssam 		if (d < 0)
83710296Ssam 			perror(local);
83811219Ssam 		break;
83911219Ssam 
84011219Ssam 	case TYPE_A:
84136935Skarels 		if (restart_point) {
84236935Skarels 			register int i, n, c;
843*36940Skarels 
84436935Skarels 			if (fseek(fout, 0L, L_SET) < 0)
84536935Skarels 				goto done;
84636935Skarels 			n = restart_point;
84736935Skarels 			i = 0;
848*36940Skarels 			while (i++ < n) {
84936935Skarels 				if ((c=getc(fout)) == EOF)
85036935Skarels 					goto done;
85136935Skarels 				if (c == '\n')
85236935Skarels 					i++;
85336935Skarels 			}
85436935Skarels 			if (fseek(fout, 0L, L_INCR) < 0) {
85536935Skarels done:
85636935Skarels 				perror(local);
85736935Skarels 				if (closefunc != NULL)
85836935Skarels 					(*closefunc)(fout);
85936935Skarels 				return;
86036935Skarels 			}
86136935Skarels 		}
86211219Ssam 		while ((c = getc(din)) != EOF) {
86327749Sminshall 			while (c == '\r') {
86411651Ssam 				while (hash && (bytes >= hashbytes)) {
86526496Sminshall 					(void) putchar('#');
86626496Sminshall 					(void) fflush(stdout);
867*36940Skarels 					hashbytes += HASHBYTES;
86811651Ssam 				}
86910296Ssam 				bytes++;
87026048Sminshall 				if ((c = getc(din)) != '\n' || tcrflag) {
871*36940Skarels 					if (ferror(fout))
872*36940Skarels 						goto break2;
873*36940Skarels 					(void) putc('\r', fout);
874*36940Skarels 					if (c == '\0' || c == EOF)
875*36940Skarels 						goto contin2;
87611219Ssam 				}
87711219Ssam 			}
878*36940Skarels 			(void) putc(c, fout);
87911219Ssam 			bytes++;
880*36940Skarels 	contin2:	;
88110296Ssam 		}
882*36940Skarels break2:
88311651Ssam 		if (hash) {
88413213Ssam 			if (bytes < hashbytes)
88526496Sminshall 				(void) putchar('#');
88626496Sminshall 			(void) putchar('\n');
88726496Sminshall 			(void) fflush(stdout);
88811651Ssam 		}
889*36940Skarels 		if (ferror(din)){
89036935Skarels 			if (errno != EPIPE)
89136935Skarels 				perror ("netin");
89236935Skarels 			bytes = -1;
89336935Skarels 		}
894*36940Skarels 		if (ferror(fout))
89511219Ssam 			perror (local);
89611219Ssam 		break;
89710296Ssam 	}
89826448Slepreau 	if (closefunc != NULL)
89926048Sminshall 		(*closefunc)(fout);
90026496Sminshall 	(void) signal(SIGINT, oldintr);
90126448Slepreau 	if (oldintp)
90226048Sminshall 		(void) signal(SIGPIPE, oldintp);
90326496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
90410296Ssam 	(void) fclose(din);
90526048Sminshall 	(void) getreply(0);
90636935Skarels 	if (bytes > 0 && is_retr)
90726048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
90826048Sminshall 	if (oldtype) {
90926448Slepreau 		if (!debug)
91026048Sminshall 			verbose = 0;
91126048Sminshall 		switch (oldtype) {
91226048Sminshall 			case TYPE_I:
91326048Sminshall 				setbinary();
91426048Sminshall 				break;
91526048Sminshall 			case TYPE_E:
91626048Sminshall 				setebcdic();
91726048Sminshall 				break;
91826048Sminshall 			case TYPE_L:
91926048Sminshall 				settenex();
92026048Sminshall 				break;
92126048Sminshall 		}
92226048Sminshall 		verbose = oldverbose;
92326048Sminshall 	}
92426048Sminshall 	return;
92526048Sminshall abort:
92626048Sminshall 
92727687Sminshall /* abort using RFC959 recommended IP,SYNC sequence  */
92826048Sminshall 
92926496Sminshall 	(void) gettimeofday(&stop, (struct timezone *)0);
93026448Slepreau 	if (oldintp)
93126048Sminshall 		(void) signal(SIGPIPE, oldintr);
93226048Sminshall 	(void) signal(SIGINT,SIG_IGN);
93326048Sminshall 	if (oldtype) {
93426448Slepreau 		if (!debug)
93526048Sminshall 			verbose = 0;
93626048Sminshall 		switch (oldtype) {
93726048Sminshall 			case TYPE_I:
93826048Sminshall 				setbinary();
93926048Sminshall 				break;
94026048Sminshall 			case TYPE_E:
94126048Sminshall 				setebcdic();
94226048Sminshall 				break;
94326048Sminshall 			case TYPE_L:
94426048Sminshall 				settenex();
94526048Sminshall 				break;
94626048Sminshall 		}
94726048Sminshall 		verbose = oldverbose;
94826048Sminshall 	}
94926048Sminshall 	if (!cpend) {
95026048Sminshall 		code = -1;
95126048Sminshall 		(void) signal(SIGINT,oldintr);
95226048Sminshall 		return;
95326048Sminshall 	}
95426048Sminshall 
95527687Sminshall 	fprintf(cout,"%c%c",IAC,IP);
95627687Sminshall 	(void) fflush(cout);
95727687Sminshall 	msg = IAC;
95827687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */
95927687Sminshall /* after urgent byte rather than before as now is protocol            */
96027687Sminshall 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
96127687Sminshall 		perror("abort");
96226048Sminshall 	}
96327687Sminshall 	fprintf(cout,"%cABOR\r\n",DM);
96426048Sminshall 	(void) fflush(cout);
96527687Sminshall 	FD_ZERO(&mask);
96626496Sminshall 	FD_SET(fileno(cin), &mask);
96726496Sminshall 	if (din) {
96826496Sminshall 		FD_SET(fileno(din), &mask);
96926496Sminshall 	}
97027687Sminshall 	if ((nfnd = empty(&mask,10)) <= 0) {
97127687Sminshall 		if (nfnd < 0) {
97227687Sminshall 			perror("abort");
97327687Sminshall 		}
97426048Sminshall 		code = -1;
97526048Sminshall 		lostpeer();
97626048Sminshall 	}
97726496Sminshall 	if (din && FD_ISSET(fileno(din), &mask)) {
978*36940Skarels 		while ((c = read(fileno(din), buf, bufsize)) > 0)
97926448Slepreau 			;
98026496Sminshall 	}
98127687Sminshall 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
98226048Sminshall 		if (data >= 0) {
98326496Sminshall 			(void) close(data);
98426048Sminshall 			data = -1;
98526048Sminshall 		}
98625907Smckusick 		(void) getreply(0);
98725907Smckusick 	}
98826048Sminshall 	(void) getreply(0);
98926048Sminshall 	code = -1;
99026048Sminshall 	if (data >= 0) {
99126048Sminshall 		(void) close(data);
99226048Sminshall 		data = -1;
99326048Sminshall 	}
99426448Slepreau 	if (closefunc != NULL && fout != NULL)
99526048Sminshall 		(*closefunc)(fout);
99626448Slepreau 	if (din)
99726048Sminshall 		(void) fclose(din);
99835699Sbostic 	if (bytes > 0)
99926048Sminshall 		ptransfer("received", bytes, &start, &stop, local, remote);
100026048Sminshall 	(void) signal(SIGINT,oldintr);
100110296Ssam }
100210296Ssam 
100310296Ssam /*
100410296Ssam  * Need to start a listen on the data channel
100510296Ssam  * before we send the command, otherwise the
100610296Ssam  * server's connect may fail.
100710296Ssam  */
100833224Sbostic int sendport = -1;
100911651Ssam 
101010296Ssam initconn()
101110296Ssam {
101210296Ssam 	register char *p, *a;
101326048Sminshall 	int result, len, tmpno = 0;
101426993Skarels 	int on = 1;
101510296Ssam 
101611651Ssam noport:
101710296Ssam 	data_addr = myctladdr;
101811651Ssam 	if (sendport)
101911651Ssam 		data_addr.sin_port = 0;	/* let system pick one */
102011651Ssam 	if (data != -1)
102111651Ssam 		(void) close (data);
102218287Sralph 	data = socket(AF_INET, SOCK_STREAM, 0);
102310296Ssam 	if (data < 0) {
102410296Ssam 		perror("ftp: socket");
102526448Slepreau 		if (tmpno)
102626048Sminshall 			sendport = 1;
102710296Ssam 		return (1);
102810296Ssam 	}
102912397Ssam 	if (!sendport)
103027687Sminshall 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
103133224Sbostic 			perror("ftp: setsockopt (reuse address)");
103212397Ssam 			goto bad;
103312397Ssam 		}
103426496Sminshall 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
103510296Ssam 		perror("ftp: bind");
103610296Ssam 		goto bad;
103710296Ssam 	}
103810296Ssam 	if (options & SO_DEBUG &&
103927687Sminshall 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
104010296Ssam 		perror("ftp: setsockopt (ignored)");
104111627Ssam 	len = sizeof (data_addr);
104211627Ssam 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
104311627Ssam 		perror("ftp: getsockname");
104410296Ssam 		goto bad;
104510296Ssam 	}
104626448Slepreau 	if (listen(data, 1) < 0)
104710296Ssam 		perror("ftp: listen");
104811651Ssam 	if (sendport) {
104911651Ssam 		a = (char *)&data_addr.sin_addr;
105011651Ssam 		p = (char *)&data_addr.sin_port;
105110296Ssam #define	UC(b)	(((int)b)&0xff)
105211651Ssam 		result =
105311651Ssam 		    command("PORT %d,%d,%d,%d,%d,%d",
105411651Ssam 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
105511651Ssam 		      UC(p[0]), UC(p[1]));
105611651Ssam 		if (result == ERROR && sendport == -1) {
105711651Ssam 			sendport = 0;
105826048Sminshall 			tmpno = 1;
105911651Ssam 			goto noport;
106011651Ssam 		}
106111651Ssam 		return (result != COMPLETE);
106211651Ssam 	}
106326448Slepreau 	if (tmpno)
106426048Sminshall 		sendport = 1;
106511651Ssam 	return (0);
106610296Ssam bad:
106710296Ssam 	(void) close(data), data = -1;
106826448Slepreau 	if (tmpno)
106926048Sminshall 		sendport = 1;
107010296Ssam 	return (1);
107110296Ssam }
107210296Ssam 
107310296Ssam FILE *
107410296Ssam dataconn(mode)
107510296Ssam 	char *mode;
107610296Ssam {
107710296Ssam 	struct sockaddr_in from;
107810296Ssam 	int s, fromlen = sizeof (from);
107910296Ssam 
108026496Sminshall 	s = accept(data, (struct sockaddr *) &from, &fromlen);
108110296Ssam 	if (s < 0) {
108210296Ssam 		perror("ftp: accept");
108310296Ssam 		(void) close(data), data = -1;
108410296Ssam 		return (NULL);
108510296Ssam 	}
108610296Ssam 	(void) close(data);
108710296Ssam 	data = s;
108810296Ssam 	return (fdopen(data, mode));
108910296Ssam }
109010296Ssam 
109126048Sminshall ptransfer(direction, bytes, t0, t1, local, remote)
109226048Sminshall 	char *direction, *local, *remote;
109311651Ssam 	long bytes;
109410296Ssam 	struct timeval *t0, *t1;
109510296Ssam {
109610296Ssam 	struct timeval td;
109716437Sleres 	float s, bs;
109810296Ssam 
109935699Sbostic 	if (verbose) {
110035699Sbostic 		tvsub(&td, t1, t0);
110135699Sbostic 		s = td.tv_sec + (td.tv_usec / 1000000.);
110210296Ssam #define	nz(x)	((x) == 0 ? 1 : (x))
110335699Sbostic 		bs = bytes / nz(s);
110435699Sbostic 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
110535699Sbostic 		    bytes, direction, s, bs / 1024.);
110635699Sbostic 	} else {
110735699Sbostic 		if (local && *local != '-')
110835699Sbostic 			printf("local: %s ", local);
110935699Sbostic 		if (remote)
111035699Sbostic 			printf("remote: %s\n", remote);
111135699Sbostic 	}
111210296Ssam }
111310296Ssam 
111426496Sminshall /*tvadd(tsum, t0)
111510296Ssam 	struct timeval *tsum, *t0;
111610296Ssam {
111710296Ssam 
111810296Ssam 	tsum->tv_sec += t0->tv_sec;
111910296Ssam 	tsum->tv_usec += t0->tv_usec;
112010296Ssam 	if (tsum->tv_usec > 1000000)
112110296Ssam 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
112226496Sminshall } */
112310296Ssam 
112410296Ssam tvsub(tdiff, t1, t0)
112510296Ssam 	struct timeval *tdiff, *t1, *t0;
112610296Ssam {
112710296Ssam 
112810296Ssam 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
112910296Ssam 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
113010296Ssam 	if (tdiff->tv_usec < 0)
113110296Ssam 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
113210296Ssam }
113326048Sminshall 
113426048Sminshall psabort()
113526048Sminshall {
113626048Sminshall 	extern int abrtflag;
113726048Sminshall 
113826048Sminshall 	abrtflag++;
113926048Sminshall }
114026048Sminshall 
114126048Sminshall pswitch(flag)
114226048Sminshall 	int flag;
114326048Sminshall {
114426048Sminshall 	extern int proxy, abrtflag;
114526048Sminshall 	int (*oldintr)();
114626048Sminshall 	static struct comvars {
114726048Sminshall 		int connect;
114828469Skarels 		char name[MAXHOSTNAMELEN];
114926048Sminshall 		struct sockaddr_in mctl;
115026048Sminshall 		struct sockaddr_in hctl;
115126048Sminshall 		FILE *in;
115226048Sminshall 		FILE *out;
115326048Sminshall 		int tpe;
115426048Sminshall 		int cpnd;
115526048Sminshall 		int sunqe;
115626048Sminshall 		int runqe;
115726048Sminshall 		int mcse;
115826048Sminshall 		int ntflg;
115926048Sminshall 		char nti[17];
116026048Sminshall 		char nto[17];
116126048Sminshall 		int mapflg;
116226048Sminshall 		char mi[MAXPATHLEN];
116326048Sminshall 		char mo[MAXPATHLEN];
116426048Sminshall 		} proxstruct, tmpstruct;
116526048Sminshall 	struct comvars *ip, *op;
116626048Sminshall 
116726048Sminshall 	abrtflag = 0;
116826048Sminshall 	oldintr = signal(SIGINT, psabort);
116926048Sminshall 	if (flag) {
117026448Slepreau 		if (proxy)
117126048Sminshall 			return;
117226048Sminshall 		ip = &tmpstruct;
117326048Sminshall 		op = &proxstruct;
117426048Sminshall 		proxy++;
117526048Sminshall 	}
117626048Sminshall 	else {
117726448Slepreau 		if (!proxy)
117826048Sminshall 			return;
117926048Sminshall 		ip = &proxstruct;
118026048Sminshall 		op = &tmpstruct;
118126048Sminshall 		proxy = 0;
118226048Sminshall 	}
118326048Sminshall 	ip->connect = connected;
118426048Sminshall 	connected = op->connect;
118528469Skarels 	if (hostname) {
118628469Skarels 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
118728469Skarels 		ip->name[strlen(ip->name)] = '\0';
118828469Skarels 	} else
118928469Skarels 		ip->name[0] = 0;
119026048Sminshall 	hostname = op->name;
119126048Sminshall 	ip->hctl = hisctladdr;
119226048Sminshall 	hisctladdr = op->hctl;
119326048Sminshall 	ip->mctl = myctladdr;
119426048Sminshall 	myctladdr = op->mctl;
119526048Sminshall 	ip->in = cin;
119626048Sminshall 	cin = op->in;
119726048Sminshall 	ip->out = cout;
119826048Sminshall 	cout = op->out;
119926048Sminshall 	ip->tpe = type;
120026048Sminshall 	type = op->tpe;
120126448Slepreau 	if (!type)
120226048Sminshall 		type = 1;
120326048Sminshall 	ip->cpnd = cpend;
120426048Sminshall 	cpend = op->cpnd;
120526048Sminshall 	ip->sunqe = sunique;
120626048Sminshall 	sunique = op->sunqe;
120726048Sminshall 	ip->runqe = runique;
120826048Sminshall 	runique = op->runqe;
120926048Sminshall 	ip->mcse = mcase;
121026048Sminshall 	mcase = op->mcse;
121126048Sminshall 	ip->ntflg = ntflag;
121226048Sminshall 	ntflag = op->ntflg;
121326496Sminshall 	(void) strncpy(ip->nti, ntin, 16);
121426048Sminshall 	(ip->nti)[strlen(ip->nti)] = '\0';
121526496Sminshall 	(void) strcpy(ntin, op->nti);
121626496Sminshall 	(void) strncpy(ip->nto, ntout, 16);
121726048Sminshall 	(ip->nto)[strlen(ip->nto)] = '\0';
121826496Sminshall 	(void) strcpy(ntout, op->nto);
121926048Sminshall 	ip->mapflg = mapflag;
122026048Sminshall 	mapflag = op->mapflg;
122126496Sminshall 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
122226048Sminshall 	(ip->mi)[strlen(ip->mi)] = '\0';
122326496Sminshall 	(void) strcpy(mapin, op->mi);
122426496Sminshall 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
122526048Sminshall 	(ip->mo)[strlen(ip->mo)] = '\0';
122626496Sminshall 	(void) strcpy(mapout, op->mo);
122726048Sminshall 	(void) signal(SIGINT, oldintr);
122826048Sminshall 	if (abrtflag) {
122926048Sminshall 		abrtflag = 0;
123026048Sminshall 		(*oldintr)();
123126448Slepreau 	}
123226048Sminshall }
123326048Sminshall 
123426048Sminshall jmp_buf ptabort;
123526048Sminshall int ptabflg;
123626048Sminshall 
123726048Sminshall abortpt()
123826048Sminshall {
123926048Sminshall 	printf("\n");
124026496Sminshall 	(void) fflush(stdout);
124126048Sminshall 	ptabflg++;
124226048Sminshall 	mflag = 0;
124326048Sminshall 	abrtflag = 0;
124426048Sminshall 	longjmp(ptabort, 1);
124526048Sminshall }
124626048Sminshall 
124726048Sminshall proxtrans(cmd, local, remote)
124826048Sminshall 	char *cmd, *local, *remote;
124926048Sminshall {
125027687Sminshall 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
125126048Sminshall 	extern jmp_buf ptabort;
125226048Sminshall 	char *cmd2;
125326496Sminshall 	struct fd_set mask;
125426048Sminshall 
125526448Slepreau 	if (strcmp(cmd, "RETR"))
125626048Sminshall 		cmd2 = "RETR";
125726448Slepreau 	else
125826048Sminshall 		cmd2 = runique ? "STOU" : "STOR";
125926048Sminshall 	if (command("PASV") != COMPLETE) {
126026048Sminshall 		printf("proxy server does not support third part transfers.\n");
126126048Sminshall 		return;
126226048Sminshall 	}
126326048Sminshall 	tmptype = type;
126426048Sminshall 	pswitch(0);
126526048Sminshall 	if (!connected) {
126626048Sminshall 		printf("No primary connection\n");
126726048Sminshall 		pswitch(1);
126826048Sminshall 		code = -1;
126926048Sminshall 		return;
127026048Sminshall 	}
127126048Sminshall 	if (type != tmptype) {
127226048Sminshall 		oldtype = type;
127326048Sminshall 		switch (tmptype) {
127426048Sminshall 			case TYPE_A:
127526048Sminshall 				setascii();
127626048Sminshall 				break;
127726048Sminshall 			case TYPE_I:
127826048Sminshall 				setbinary();
127926048Sminshall 				break;
128026048Sminshall 			case TYPE_E:
128126048Sminshall 				setebcdic();
128226048Sminshall 				break;
128326048Sminshall 			case TYPE_L:
128426048Sminshall 				settenex();
128526048Sminshall 				break;
128626048Sminshall 		}
128726048Sminshall 	}
128826048Sminshall 	if (command("PORT %s", pasv) != COMPLETE) {
128926048Sminshall 		switch (oldtype) {
129026048Sminshall 			case 0:
129126048Sminshall 				break;
129226048Sminshall 			case TYPE_A:
129326048Sminshall 				setascii();
129426048Sminshall 				break;
129526048Sminshall 			case TYPE_I:
129626048Sminshall 				setbinary();
129726048Sminshall 				break;
129826048Sminshall 			case TYPE_E:
129926048Sminshall 				setebcdic();
130026048Sminshall 				break;
130126048Sminshall 			case TYPE_L:
130226048Sminshall 				settenex();
130326048Sminshall 				break;
130426048Sminshall 		}
130526048Sminshall 		pswitch(1);
130626048Sminshall 		return;
130726048Sminshall 	}
130826448Slepreau 	if (setjmp(ptabort))
130926048Sminshall 		goto abort;
131026048Sminshall 	oldintr = signal(SIGINT, abortpt);
131126048Sminshall 	if (command("%s %s", cmd, remote) != PRELIM) {
131226048Sminshall 		(void) signal(SIGINT, oldintr);
131326048Sminshall 		switch (oldtype) {
131426048Sminshall 			case 0:
131526048Sminshall 				break;
131626048Sminshall 			case TYPE_A:
131726048Sminshall 				setascii();
131826048Sminshall 				break;
131926048Sminshall 			case TYPE_I:
132026048Sminshall 				setbinary();
132126048Sminshall 				break;
132226048Sminshall 			case TYPE_E:
132326048Sminshall 				setebcdic();
132426048Sminshall 				break;
132526048Sminshall 			case TYPE_L:
132626048Sminshall 				settenex();
132726048Sminshall 				break;
132826048Sminshall 		}
132926048Sminshall 		pswitch(1);
133026048Sminshall 		return;
133126048Sminshall 	}
133226048Sminshall 	sleep(2);
133326048Sminshall 	pswitch(1);
133426048Sminshall 	secndflag++;
133526448Slepreau 	if (command("%s %s", cmd2, local) != PRELIM)
133626048Sminshall 		goto abort;
133726048Sminshall 	ptflag++;
133826048Sminshall 	(void) getreply(0);
133926048Sminshall 	pswitch(0);
134026048Sminshall 	(void) getreply(0);
134126048Sminshall 	(void) signal(SIGINT, oldintr);
134226048Sminshall 	switch (oldtype) {
134326048Sminshall 		case 0:
134426048Sminshall 			break;
134526048Sminshall 		case TYPE_A:
134626048Sminshall 			setascii();
134726048Sminshall 			break;
134826048Sminshall 		case TYPE_I:
134926048Sminshall 			setbinary();
135026048Sminshall 			break;
135126048Sminshall 		case TYPE_E:
135226048Sminshall 			setebcdic();
135326048Sminshall 			break;
135426048Sminshall 		case TYPE_L:
135526048Sminshall 			settenex();
135626048Sminshall 			break;
135726048Sminshall 	}
135826048Sminshall 	pswitch(1);
135926048Sminshall 	ptflag = 0;
136026048Sminshall 	printf("local: %s remote: %s\n", local, remote);
136126048Sminshall 	return;
136226048Sminshall abort:
136326048Sminshall 	(void) signal(SIGINT, SIG_IGN);
136426048Sminshall 	ptflag = 0;
136526448Slepreau 	if (strcmp(cmd, "RETR") && !proxy)
136626048Sminshall 		pswitch(1);
136726448Slepreau 	else if (!strcmp(cmd, "RETR") && proxy)
136826048Sminshall 		pswitch(0);
136926048Sminshall 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
137026048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
137126048Sminshall 			pswitch(0);
137226048Sminshall 			switch (oldtype) {
137326048Sminshall 				case 0:
137426048Sminshall 					break;
137526048Sminshall 				case TYPE_A:
137626048Sminshall 					setascii();
137726048Sminshall 					break;
137826048Sminshall 				case TYPE_I:
137926048Sminshall 					setbinary();
138026048Sminshall 					break;
138126048Sminshall 				case TYPE_E:
138226048Sminshall 					setebcdic();
138326048Sminshall 					break;
138426048Sminshall 				case TYPE_L:
138526048Sminshall 					settenex();
138626048Sminshall 					break;
138726048Sminshall 			}
138827687Sminshall 			if (cpend) {
138926048Sminshall 				char msg[2];
139026048Sminshall 
139126048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
139226048Sminshall 				(void) fflush(cout);
139326048Sminshall 				*msg = IAC;
139426048Sminshall 				*(msg+1) = DM;
139526448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
139626048Sminshall 					perror("abort");
139726048Sminshall 				fprintf(cout,"ABOR\r\n");
139826048Sminshall 				(void) fflush(cout);
139927687Sminshall 				FD_ZERO(&mask);
140026496Sminshall 				FD_SET(fileno(cin), &mask);
140127687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
140227687Sminshall 					if (nfnd < 0) {
140327687Sminshall 						perror("abort");
140427687Sminshall 					}
140526448Slepreau 					if (ptabflg)
140626048Sminshall 						code = -1;
140726048Sminshall 					lostpeer();
140826048Sminshall 				}
140926048Sminshall 				(void) getreply(0);
141026048Sminshall 				(void) getreply(0);
141126048Sminshall 			}
141226048Sminshall 		}
141326048Sminshall 		pswitch(1);
141426448Slepreau 		if (ptabflg)
141526048Sminshall 			code = -1;
141626048Sminshall 		(void) signal(SIGINT, oldintr);
141726048Sminshall 		return;
141826048Sminshall 	}
141927687Sminshall 	if (cpend) {
142026048Sminshall 		char msg[2];
142126048Sminshall 
142226048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
142326048Sminshall 		(void) fflush(cout);
142426048Sminshall 		*msg = IAC;
142526048Sminshall 		*(msg+1) = DM;
142626448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
142726048Sminshall 			perror("abort");
142826048Sminshall 		fprintf(cout,"ABOR\r\n");
142926048Sminshall 		(void) fflush(cout);
143027687Sminshall 		FD_ZERO(&mask);
143126496Sminshall 		FD_SET(fileno(cin), &mask);
143227687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
143327687Sminshall 			if (nfnd < 0) {
143427687Sminshall 				perror("abort");
143527687Sminshall 			}
143626448Slepreau 			if (ptabflg)
143726048Sminshall 				code = -1;
143826048Sminshall 			lostpeer();
143926048Sminshall 		}
144026048Sminshall 		(void) getreply(0);
144126048Sminshall 		(void) getreply(0);
144226048Sminshall 	}
144326048Sminshall 	pswitch(!proxy);
144426048Sminshall 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
144526048Sminshall 		if (command("%s %s", cmd2, local) != PRELIM) {
144626048Sminshall 			pswitch(0);
144726048Sminshall 			switch (oldtype) {
144826048Sminshall 				case 0:
144926048Sminshall 					break;
145026048Sminshall 				case TYPE_A:
145126048Sminshall 					setascii();
145226048Sminshall 					break;
145326048Sminshall 				case TYPE_I:
145426048Sminshall 					setbinary();
145526048Sminshall 					break;
145626048Sminshall 				case TYPE_E:
145726048Sminshall 					setebcdic();
145826048Sminshall 					break;
145926048Sminshall 				case TYPE_L:
146026048Sminshall 					settenex();
146126048Sminshall 					break;
146226048Sminshall 			}
146327687Sminshall 			if (cpend) {
146426048Sminshall 				char msg[2];
146526048Sminshall 
146626048Sminshall 				fprintf(cout,"%c%c",IAC,IP);
146726048Sminshall 				(void) fflush(cout);
146826048Sminshall 				*msg = IAC;
146926048Sminshall 				*(msg+1) = DM;
147026448Slepreau 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
147126048Sminshall 					perror("abort");
147226048Sminshall 				fprintf(cout,"ABOR\r\n");
147326048Sminshall 				(void) fflush(cout);
147427687Sminshall 				FD_ZERO(&mask);
147526496Sminshall 				FD_SET(fileno(cin), &mask);
147627687Sminshall 				if ((nfnd = empty(&mask,10)) <= 0) {
147727687Sminshall 					if (nfnd < 0) {
147827687Sminshall 						perror("abort");
147927687Sminshall 					}
148026448Slepreau 					if (ptabflg)
148126048Sminshall 						code = -1;
148226048Sminshall 					lostpeer();
148326048Sminshall 				}
148426048Sminshall 				(void) getreply(0);
148526048Sminshall 				(void) getreply(0);
148626048Sminshall 			}
148726048Sminshall 			pswitch(1);
148826448Slepreau 			if (ptabflg)
148926048Sminshall 				code = -1;
149026048Sminshall 			(void) signal(SIGINT, oldintr);
149126048Sminshall 			return;
149226048Sminshall 		}
149326048Sminshall 	}
149427687Sminshall 	if (cpend) {
149526048Sminshall 		char msg[2];
149626048Sminshall 
149726048Sminshall 		fprintf(cout,"%c%c",IAC,IP);
149826048Sminshall 		(void) fflush(cout);
149926048Sminshall 		*msg = IAC;
150026048Sminshall 		*(msg+1) = DM;
150126448Slepreau 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
150226048Sminshall 			perror("abort");
150326048Sminshall 		fprintf(cout,"ABOR\r\n");
150426048Sminshall 		(void) fflush(cout);
150527687Sminshall 		FD_ZERO(&mask);
150626496Sminshall 		FD_SET(fileno(cin), &mask);
150727687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
150827687Sminshall 			if (nfnd < 0) {
150927687Sminshall 				perror("abort");
151027687Sminshall 			}
151126448Slepreau 			if (ptabflg)
151226048Sminshall 				code = -1;
151326048Sminshall 			lostpeer();
151426048Sminshall 		}
151526048Sminshall 		(void) getreply(0);
151626048Sminshall 		(void) getreply(0);
151726048Sminshall 	}
151826048Sminshall 	pswitch(!proxy);
151926048Sminshall 	if (cpend) {
152027687Sminshall 		FD_ZERO(&mask);
152126496Sminshall 		FD_SET(fileno(cin), &mask);
152227687Sminshall 		if ((nfnd = empty(&mask,10)) <= 0) {
152327687Sminshall 			if (nfnd < 0) {
152427687Sminshall 				perror("abort");
152527687Sminshall 			}
152626448Slepreau 			if (ptabflg)
152726048Sminshall 				code = -1;
152826048Sminshall 			lostpeer();
152926048Sminshall 		}
153026048Sminshall 		(void) getreply(0);
153126048Sminshall 		(void) getreply(0);
153226048Sminshall 	}
153326448Slepreau 	if (proxy)
153426048Sminshall 		pswitch(0);
153526048Sminshall 	switch (oldtype) {
153626048Sminshall 		case 0:
153726048Sminshall 			break;
153826048Sminshall 		case TYPE_A:
153926048Sminshall 			setascii();
154026048Sminshall 			break;
154126048Sminshall 		case TYPE_I:
154226048Sminshall 			setbinary();
154326048Sminshall 			break;
154426048Sminshall 		case TYPE_E:
154526048Sminshall 			setebcdic();
154626048Sminshall 			break;
154726048Sminshall 		case TYPE_L:
154826048Sminshall 			settenex();
154926048Sminshall 			break;
155026048Sminshall 	}
155126048Sminshall 	pswitch(1);
155226448Slepreau 	if (ptabflg)
155326048Sminshall 		code = -1;
155426048Sminshall 	(void) signal(SIGINT, oldintr);
155526048Sminshall }
155626048Sminshall 
155726048Sminshall reset()
155826048Sminshall {
155926496Sminshall 	struct fd_set mask;
156026496Sminshall 	int nfnd = 1;
156126048Sminshall 
156227687Sminshall 	FD_ZERO(&mask);
156330946Scsvsj 	while (nfnd > 0) {
156426496Sminshall 		FD_SET(fileno(cin), &mask);
156527687Sminshall 		if ((nfnd = empty(&mask,0)) < 0) {
156626048Sminshall 			perror("reset");
156726048Sminshall 			code = -1;
156826048Sminshall 			lostpeer();
156926048Sminshall 		}
157027687Sminshall 		else if (nfnd) {
157126048Sminshall 			(void) getreply(0);
157226496Sminshall 		}
157326048Sminshall 	}
157426048Sminshall }
157526048Sminshall 
157626048Sminshall char *
157726048Sminshall gunique(local)
157826048Sminshall 	char *local;
157926048Sminshall {
158026048Sminshall 	static char new[MAXPATHLEN];
158126048Sminshall 	char *cp = rindex(local, '/');
158226048Sminshall 	int d, count=0;
158326048Sminshall 	char ext = '1';
158426048Sminshall 
158526448Slepreau 	if (cp)
158626048Sminshall 		*cp = '\0';
158726048Sminshall 	d = access(cp ? local : ".", 2);
158826448Slepreau 	if (cp)
158926048Sminshall 		*cp = '/';
159026048Sminshall 	if (d < 0) {
159126048Sminshall 		perror(local);
159226048Sminshall 		return((char *) 0);
159326048Sminshall 	}
159426048Sminshall 	(void) strcpy(new, local);
159526048Sminshall 	cp = new + strlen(new);
159626048Sminshall 	*cp++ = '.';
159726048Sminshall 	while (!d) {
159826048Sminshall 		if (++count == 100) {
159926048Sminshall 			printf("runique: can't find unique file name.\n");
160026048Sminshall 			return((char *) 0);
160126048Sminshall 		}
160226048Sminshall 		*cp++ = ext;
160326048Sminshall 		*cp = '\0';
160426448Slepreau 		if (ext == '9')
160526048Sminshall 			ext = '0';
160626448Slepreau 		else
160726048Sminshall 			ext++;
160826448Slepreau 		if ((d = access(new, 0)) < 0)
160926048Sminshall 			break;
161026448Slepreau 		if (ext != '0')
161126048Sminshall 			cp--;
161226448Slepreau 		else if (*(cp - 2) == '.')
161326048Sminshall 			*(cp - 1) = '1';
161426048Sminshall 		else {
161526048Sminshall 			*(cp - 2) = *(cp - 2) + 1;
161626048Sminshall 			cp--;
161726048Sminshall 		}
161826048Sminshall 	}
161926048Sminshall 	return(new);
162026048Sminshall }
1621