xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 36945)
1 /*
2  * Copyright (c) 1985, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)ftp.c	5.24.1.3 (Berkeley) 03/01/89";
20 #endif /* not lint */
21 
22 #include <sys/param.h>
23 #include <sys/stat.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/time.h>
27 #include <sys/file.h>
28 
29 #include <netinet/in.h>
30 #include <arpa/ftp.h>
31 #include <arpa/telnet.h>
32 
33 #include <stdio.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #include <fcntl.h>
38 #include <pwd.h>
39 
40 #include "ftp_var.h"
41 
42 struct	sockaddr_in hisctladdr;
43 struct	sockaddr_in data_addr;
44 int	data = -1;
45 int	abrtflag = 0;
46 int	ptflag = 0;
47 int	connected;
48 struct	sockaddr_in myctladdr;
49 uid_t	getuid();
50 
51 FILE	*cin, *cout;
52 FILE	*dataconn();
53 
54 char *
55 hookup(host, port)
56 	char *host;
57 	int port;
58 {
59 	register struct hostent *hp = 0;
60 	int s,len;
61 	static char hostnamebuf[80];
62 
63 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
64 	hisctladdr.sin_addr.s_addr = inet_addr(host);
65 	if (hisctladdr.sin_addr.s_addr != -1) {
66 		hisctladdr.sin_family = AF_INET;
67 		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
68 	} else {
69 		hp = gethostbyname(host);
70 		if (hp == NULL) {
71 			fprintf(stderr, "ftp: %s: ", host);
72 			herror((char *)NULL);
73 			code = -1;
74 			return((char *) 0);
75 		}
76 		hisctladdr.sin_family = hp->h_addrtype;
77 		bcopy(hp->h_addr_list[0],
78 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
79 		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
80 	}
81 	hostname = hostnamebuf;
82 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
83 	if (s < 0) {
84 		perror("ftp: socket");
85 		code = -1;
86 		return (0);
87 	}
88 	hisctladdr.sin_port = port;
89 	while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) {
90 		if (hp && hp->h_addr_list[1]) {
91 			int oerrno = errno;
92 
93 			fprintf(stderr, "ftp: connect to address %s: ",
94 				inet_ntoa(hisctladdr.sin_addr));
95 			errno = oerrno;
96 			perror((char *) 0);
97 			hp->h_addr_list++;
98 			bcopy(hp->h_addr_list[0],
99 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
100 			fprintf(stdout, "Trying %s...\n",
101 				inet_ntoa(hisctladdr.sin_addr));
102 			(void) close(s);
103 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
104 			if (s < 0) {
105 				perror("ftp: socket");
106 				code = -1;
107 				return (0);
108 			}
109 			continue;
110 		}
111 		perror("ftp: connect");
112 		code = -1;
113 		goto bad;
114 	}
115 	len = sizeof (myctladdr);
116 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
117 		perror("ftp: getsockname");
118 		code = -1;
119 		goto bad;
120 	}
121 	cin = fdopen(s, "r");
122 	cout = fdopen(s, "w");
123 	if (cin == NULL || cout == NULL) {
124 		fprintf(stderr, "ftp: fdopen failed.\n");
125 		if (cin)
126 			(void) fclose(cin);
127 		if (cout)
128 			(void) fclose(cout);
129 		code = -1;
130 		goto bad;
131 	}
132 	if (verbose)
133 		printf("Connected to %s.\n", hostname);
134 	if (getreply(0) > 2) { 	/* read startup message from server */
135 		if (cin)
136 			(void) fclose(cin);
137 		if (cout)
138 			(void) fclose(cout);
139 		code = -1;
140 		goto bad;
141 	}
142 #ifdef SO_OOBINLINE
143 	{
144 	int on = 1;
145 
146 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on))
147 		< 0 && debug) {
148 			perror("ftp: setsockopt");
149 		}
150 	}
151 #endif SO_OOBINLINE
152 
153 	return (hostname);
154 bad:
155 	(void) close(s);
156 	return ((char *)0);
157 }
158 
159 login(host)
160 	char *host;
161 {
162 	char tmp[80];
163 	char *user, *pass, *acct, *getlogin(), *getpass();
164 	int n, aflag = 0;
165 
166 	user = pass = acct = 0;
167 	if (ruserpass(host, &user, &pass, &acct) < 0) {
168 		code = -1;
169 		return(0);
170 	}
171 	if (user == NULL) {
172 		char *myname = getlogin();
173 
174 		if (myname == NULL) {
175 			struct passwd *pp = getpwuid(getuid());
176 
177 			if (pp != NULL)
178 				myname = pp->pw_name;
179 		}
180 		printf("Name (%s:%s): ", host, myname);
181 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
182 		tmp[strlen(tmp) - 1] = '\0';
183 		if (*tmp == '\0')
184 			user = myname;
185 		else
186 			user = tmp;
187 	}
188 	n = command("USER %s", user);
189 	if (n == CONTINUE) {
190 		if (pass == NULL)
191 			pass = getpass("Password:");
192 		n = command("PASS %s", pass);
193 	}
194 	if (n == CONTINUE) {
195 		aflag++;
196 		acct = getpass("Account:");
197 		n = command("ACCT %s", acct);
198 	}
199 	if (n != COMPLETE) {
200 		fprintf(stderr, "Login failed.\n");
201 		return (0);
202 	}
203 	if (!aflag && acct != NULL)
204 		(void) command("ACCT %s", acct);
205 	if (proxy)
206 		return(1);
207 	for (n = 0; n < macnum; ++n) {
208 		if (!strcmp("init", macros[n].mac_name)) {
209 			(void) strcpy(line, "$init");
210 			makeargv();
211 			domacro(margc, margv);
212 			break;
213 		}
214 	}
215 	return (1);
216 }
217 
218 cmdabort()
219 {
220 	extern jmp_buf ptabort;
221 
222 	printf("\n");
223 	(void) fflush(stdout);
224 	abrtflag++;
225 	if (ptflag)
226 		longjmp(ptabort,1);
227 }
228 
229 /*VARARGS1*/
230 command(fmt, args)
231 	char *fmt;
232 {
233 	int r, (*oldintr)(), cmdabort();
234 
235 	abrtflag = 0;
236 	if (debug) {
237 		printf("---> ");
238 		_doprnt(fmt, &args, stdout);
239 		printf("\n");
240 		(void) fflush(stdout);
241 	}
242 	if (cout == NULL) {
243 		perror ("No control connection for command");
244 		code = -1;
245 		return (0);
246 	}
247 	oldintr = signal(SIGINT,cmdabort);
248 	_doprnt(fmt, &args, cout);
249 	fprintf(cout, "\r\n");
250 	(void) fflush(cout);
251 	cpend = 1;
252 	r = getreply(!strcmp(fmt, "QUIT"));
253 	if (abrtflag && oldintr != SIG_IGN)
254 		(*oldintr)();
255 	(void) signal(SIGINT, oldintr);
256 	return(r);
257 }
258 
259 char reply_string[BUFSIZ];
260 
261 #include <ctype.h>
262 
263 getreply(expecteof)
264 	int expecteof;
265 {
266 	register int c, n;
267 	register int dig;
268 	register char *cp;
269 	int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort();
270 	int pflag = 0;
271 	char *pt = pasv;
272 
273 	cp = reply_string;
274 	oldintr = signal(SIGINT,cmdabort);
275 	for (;;) {
276 		dig = n = code = 0;
277 		while ((c = getc(cin)) != '\n') {
278 			if (c == IAC) {     /* handle telnet commands */
279 				switch (c = getc(cin)) {
280 				case WILL:
281 				case WONT:
282 					c = getc(cin);
283 					fprintf(cout, "%c%c%c",IAC,DONT,c);
284 					(void) fflush(cout);
285 					break;
286 				case DO:
287 				case DONT:
288 					c = getc(cin);
289 					fprintf(cout, "%c%c%c",IAC,WONT,c);
290 					(void) fflush(cout);
291 					break;
292 				default:
293 					break;
294 				}
295 				continue;
296 			}
297 			dig++;
298 			if (c == EOF) {
299 				if (expecteof) {
300 					(void) signal(SIGINT,oldintr);
301 					code = 221;
302 					return (0);
303 				}
304 				lostpeer();
305 				if (verbose) {
306 					printf("421 Service not available, remote server has closed connection\n");
307 					(void) fflush(stdout);
308 				}
309 				code = 421;
310 				return(4);
311 			}
312 			if (c != '\r' && (verbose > 0 ||
313 			    (verbose > -1 && n == '5' && dig > 4))) {
314 				if (proxflag &&
315 				   (dig == 1 || dig == 5 && verbose == 0))
316 					printf("%s:",hostname);
317 				(void) putchar(c);
318 			}
319 			if (dig < 4 && isdigit(c))
320 				code = code * 10 + (c - '0');
321 			if (!pflag && code == 227)
322 				pflag = 1;
323 			if (dig > 4 && pflag == 1 && isdigit(c))
324 				pflag = 2;
325 			if (pflag == 2) {
326 				if (c != '\r' && c != ')')
327 					*pt++ = c;
328 				else {
329 					*pt = '\0';
330 					pflag = 3;
331 				}
332 			}
333 			if (dig == 4 && c == '-') {
334 				if (continuation)
335 					code = 0;
336 				continuation++;
337 			}
338 			if (n == 0)
339 				n = c;
340 			*cp++ = c;
341 		}
342 		if (verbose > 0 || verbose > -1 && n == '5') {
343 			(void) putchar(c);
344 			(void) fflush (stdout);
345 		}
346 		if (continuation && code != originalcode) {
347 			if (originalcode == 0)
348 				originalcode = code;
349 			continue;
350 		}
351 		*cp = '\0';
352 		if (n != '1')
353 			cpend = 0;
354 		(void) signal(SIGINT,oldintr);
355 		if (code == 421 || originalcode == 421)
356 			lostpeer();
357 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
358 			(*oldintr)();
359 		return (n - '0');
360 	}
361 }
362 
363 empty(mask, sec)
364 	struct fd_set *mask;
365 	int sec;
366 {
367 	struct timeval t;
368 
369 	t.tv_sec = (long) sec;
370 	t.tv_usec = 0;
371 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
372 }
373 
374 jmp_buf	sendabort;
375 
376 abortsend()
377 {
378 
379 	mflag = 0;
380 	abrtflag = 0;
381 	printf("\nsend aborted\n");
382 	(void) fflush(stdout);
383 	longjmp(sendabort, 1);
384 }
385 
386 #define HASHBYTES 1024
387 
388 sendrequest(cmd, local, remote)
389 	char *cmd, *local, *remote;
390 {
391 	FILE *fin, *dout = 0, *popen();
392 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
393 	int abortsend();
394 	char buf[BUFSIZ], *bufp;
395 	long bytes = 0, hashbytes = HASHBYTES;
396 	register int c, d;
397 	struct stat st;
398 	struct timeval start, stop;
399 	char *mode;
400 
401 	if (proxy) {
402 		proxtrans(cmd, local, remote);
403 		return;
404 	}
405 	closefunc = NULL;
406 	oldintr = NULL;
407 	oldintp = NULL;
408 	mode = "w";
409 	if (setjmp(sendabort)) {
410 		while (cpend) {
411 			(void) getreply(0);
412 		}
413 		if (data >= 0) {
414 			(void) close(data);
415 			data = -1;
416 		}
417 		if (oldintr)
418 			(void) signal(SIGINT,oldintr);
419 		if (oldintp)
420 			(void) signal(SIGPIPE,oldintp);
421 		code = -1;
422 		return;
423 	}
424 	oldintr = signal(SIGINT, abortsend);
425 	if (strcmp(local, "-") == 0)
426 		fin = stdin;
427 	else if (*local == '|') {
428 		oldintp = signal(SIGPIPE,SIG_IGN);
429 		fin = popen(local + 1, "r");
430 		if (fin == NULL) {
431 			perror(local + 1);
432 			(void) signal(SIGINT, oldintr);
433 			(void) signal(SIGPIPE, oldintp);
434 			code = -1;
435 			return;
436 		}
437 		closefunc = pclose;
438 	} else {
439 		fin = fopen(local, "r");
440 		if (fin == NULL) {
441 			perror(local);
442 			(void) signal(SIGINT, oldintr);
443 			code = -1;
444 			return;
445 		}
446 		closefunc = fclose;
447 		if (fstat(fileno(fin), &st) < 0 ||
448 		    (st.st_mode&S_IFMT) != S_IFREG) {
449 			fprintf(stdout, "%s: not a plain file.\n", local);
450 			(void) signal(SIGINT, oldintr);
451 			fclose(fin);
452 			code = -1;
453 			return;
454 		}
455 	}
456 	if (initconn()) {
457 		(void) signal(SIGINT, oldintr);
458 		if (oldintp)
459 			(void) signal(SIGPIPE, oldintp);
460 		code = -1;
461 		if (closefunc != NULL)
462 			(*closefunc)(fin);
463 		return;
464 	}
465 	if (setjmp(sendabort))
466 		goto abort;
467 
468 	if (remote) {
469 		if (command("%s %s", cmd, remote) != PRELIM) {
470 			(void) signal(SIGINT, oldintr);
471 			if (oldintp)
472 				(void) signal(SIGPIPE, oldintp);
473 			if (closefunc != NULL)
474 				(*closefunc)(fin);
475 			return;
476 		}
477 	} else
478 		if (command("%s", cmd) != PRELIM) {
479 			(void) signal(SIGINT, oldintr);
480 			if (oldintp)
481 				(void) signal(SIGPIPE, oldintp);
482 			if (closefunc != NULL)
483 				(*closefunc)(fin);
484 			return;
485 		}
486 	dout = dataconn(mode);
487 	if (dout == NULL)
488 		goto abort;
489 	(void) gettimeofday(&start, (struct timezone *)0);
490 	oldintp = signal(SIGPIPE, SIG_IGN);
491 	switch (type) {
492 
493 	case TYPE_I:
494 	case TYPE_L:
495 		errno = d = 0;
496 		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
497 			bytes += c;
498 			for (bufp = buf; c > 0; c -= d, bufp += d)
499 				if ((d = write(fileno(dout), bufp, c)) <= 0)
500 					break;
501 			if (hash) {
502 				while (bytes >= hashbytes) {
503 					(void) putchar('#');
504 					hashbytes += HASHBYTES;
505 				}
506 				(void) fflush(stdout);
507 			}
508 		}
509 		if (hash && bytes > 0) {
510 			if (bytes < HASHBYTES)
511 				(void) putchar('#');
512 			(void) putchar('\n');
513 			(void) fflush(stdout);
514 		}
515 		if (c < 0)
516 			perror(local);
517 		if (d <= 0) {
518 			if (d == 0)
519 				fprintf(stderr, "netout: write returned 0?\n");
520 			else if (errno != EPIPE)
521 				perror("netout");
522 			bytes = -1;
523 		}
524 		break;
525 
526 	case TYPE_A:
527 		while ((c = getc(fin)) != EOF) {
528 			if (c == '\n') {
529 				while (hash && (bytes >= hashbytes)) {
530 					(void) putchar('#');
531 					(void) fflush(stdout);
532 					hashbytes += HASHBYTES;
533 				}
534 				if (ferror(dout))
535 					break;
536 				(void) putc('\r', dout);
537 				bytes++;
538 			}
539 			(void) putc(c, dout);
540 			bytes++;
541 	/*		if (c == '\r') {			  	*/
542 	/*		(void)	putc('\0', dout);  /* this violates rfc */
543 	/*			bytes++;				*/
544 	/*		}                          			*/
545 		}
546 		if (hash) {
547 			if (bytes < hashbytes)
548 				(void) putchar('#');
549 			(void) putchar('\n');
550 			(void) fflush(stdout);
551 		}
552 		if (ferror(fin))
553 			perror(local);
554 		if (ferror(dout)) {
555 			if (errno != EPIPE)
556 				perror("netout");
557 			bytes = -1;
558 		}
559 		break;
560 	}
561 	(void) gettimeofday(&stop, (struct timezone *)0);
562 	if (closefunc != NULL)
563 		(*closefunc)(fin);
564 	(void) fclose(dout);
565 	(void) getreply(0);
566 	(void) signal(SIGINT, oldintr);
567 	if (oldintp)
568 		(void) signal(SIGPIPE, oldintp);
569 	if (bytes > 0)
570 		ptransfer("sent", bytes, &start, &stop, local, remote);
571 	return;
572 abort:
573 	(void) gettimeofday(&stop, (struct timezone *)0);
574 	(void) signal(SIGINT, oldintr);
575 	if (oldintp)
576 		(void) signal(SIGPIPE, oldintp);
577 	if (!cpend) {
578 		code = -1;
579 		return;
580 	}
581 	if (data >= 0) {
582 		(void) close(data);
583 		data = -1;
584 	}
585 	if (dout)
586 		(void) fclose(dout);
587 	(void) getreply(0);
588 	code = -1;
589 	if (closefunc != NULL && fin != NULL)
590 		(*closefunc)(fin);
591 	if (bytes > 0)
592 		ptransfer("sent", bytes, &start, &stop, local, remote);
593 }
594 
595 jmp_buf	recvabort;
596 
597 abortrecv()
598 {
599 
600 	mflag = 0;
601 	abrtflag = 0;
602 	printf("\n");
603 	(void) fflush(stdout);
604 	longjmp(recvabort, 1);
605 }
606 
607 recvrequest(cmd, local, remote, mode)
608 	char *cmd, *local, *remote, *mode;
609 {
610 	FILE *fout, *din = 0, *popen();
611 	int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)();
612 	int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd;
613 	char *bufp, *gunique(), msg;
614 	static char *buf;
615 	static int bufsize;
616 	long bytes = 0, hashbytes = HASHBYTES;
617 	struct fd_set mask;
618 	register int c, d;
619 	struct timeval start, stop;
620 	struct stat st;
621 	extern char *malloc();
622 
623 	is_retr = strcmp(cmd, "RETR") == 0;
624 	if (proxy && is_retr) {
625 		proxtrans(cmd, local, remote);
626 		return;
627 	}
628 	closefunc = NULL;
629 	oldintr = NULL;
630 	oldintp = NULL;
631 	tcrflag = !crflag && is_retr;
632 	if (setjmp(recvabort)) {
633 		while (cpend) {
634 			(void) getreply(0);
635 		}
636 		if (data >= 0) {
637 			(void) close(data);
638 			data = -1;
639 		}
640 		if (oldintr)
641 			(void) signal(SIGINT, oldintr);
642 		code = -1;
643 		return;
644 	}
645 	oldintr = signal(SIGINT, abortrecv);
646 	if (strcmp(local, "-") && *local != '|') {
647 		if (access(local, 2) < 0) {
648 			char *dir = rindex(local, '/');
649 
650 			if (errno != ENOENT && errno != EACCES) {
651 				perror(local);
652 				(void) signal(SIGINT, oldintr);
653 				code = -1;
654 				return;
655 			}
656 			if (dir != NULL)
657 				*dir = 0;
658 			d = access(dir ? local : ".", 2);
659 			if (dir != NULL)
660 				*dir = '/';
661 			if (d < 0) {
662 				perror(local);
663 				(void) signal(SIGINT, oldintr);
664 				code = -1;
665 				return;
666 			}
667 			if (!runique && errno == EACCES &&
668 			    chmod(local, 0600) < 0) {
669 				perror(local);
670 				(void) signal(SIGINT, oldintr);
671 				code = -1;
672 				return;
673 			}
674 			if (runique && errno == EACCES &&
675 			   (local = gunique(local)) == NULL) {
676 				(void) signal(SIGINT, oldintr);
677 				code = -1;
678 				return;
679 			}
680 		}
681 		else if (runique && (local = gunique(local)) == NULL) {
682 			(void) signal(SIGINT, oldintr);
683 			code = -1;
684 			return;
685 		}
686 	}
687 	if (initconn()) {
688 		(void) signal(SIGINT, oldintr);
689 		code = -1;
690 		return;
691 	}
692 	if (setjmp(recvabort))
693 		goto abort;
694 	if (!is_retr) {
695 		if (type != TYPE_A) {
696 			oldtype = type;
697 			oldverbose = verbose;
698 			if (!debug)
699 				verbose = 0;
700 			setascii();
701 			verbose = oldverbose;
702 		}
703 	}
704 	if (remote) {
705 		if (command("%s %s", cmd, remote) != PRELIM) {
706 			(void) signal(SIGINT, oldintr);
707 			if (oldtype) {
708 				if (!debug)
709 					verbose = 0;
710 				switch (oldtype) {
711 					case TYPE_I:
712 						setbinary();
713 						break;
714 					case TYPE_E:
715 						setebcdic();
716 						break;
717 					case TYPE_L:
718 						settenex();
719 						break;
720 				}
721 				verbose = oldverbose;
722 			}
723 			return;
724 		}
725 	} else {
726 		if (command("%s", cmd) != PRELIM) {
727 			(void) signal(SIGINT, oldintr);
728 			if (oldtype) {
729 				if (!debug)
730 					verbose = 0;
731 				switch (oldtype) {
732 					case TYPE_I:
733 						setbinary();
734 						break;
735 					case TYPE_E:
736 						setebcdic();
737 						break;
738 					case TYPE_L:
739 						settenex();
740 						break;
741 				}
742 				verbose = oldverbose;
743 			}
744 			return;
745 		}
746 	}
747 	din = dataconn("r");
748 	if (din == NULL)
749 		goto abort;
750 	if (strcmp(local, "-") == 0)
751 		fout = stdout;
752 	else if (*local == '|') {
753 		oldintp = signal(SIGPIPE, SIG_IGN);
754 		fout = popen(local + 1, "w");
755 		if (fout == NULL) {
756 			perror(local+1);
757 			goto abort;
758 		}
759 		closefunc = pclose;
760 	} else {
761 		fout = fopen(local, mode);
762 		if (fout == NULL) {
763 			perror(local);
764 			goto abort;
765 		}
766 		closefunc = fclose;
767 	}
768 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
769 		st.st_blksize = BUFSIZ;
770 	if (st.st_blksize > bufsize) {
771 		if (buf)
772 			(void) free(buf);
773 		buf = malloc(st.st_blksize);
774 		if (buf == NULL) {
775 			perror("malloc");
776 			bufsize = 0;
777 			goto abort;
778 		}
779 		bufsize = st.st_blksize;
780 	}
781 	(void) gettimeofday(&start, (struct timezone *)0);
782 	switch (type) {
783 
784 	case TYPE_I:
785 	case TYPE_L:
786 		errno = d = 0;
787 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
788 			if ((d = write(fileno(fout), buf, c)) != c)
789 				break;
790 			bytes += c;
791 			if (hash) {
792 				while (bytes >= hashbytes) {
793 					(void) putchar('#');
794 					hashbytes += HASHBYTES;
795 				}
796 				(void) fflush(stdout);
797 			}
798 		}
799 		if (hash && bytes > 0) {
800 			if (bytes < HASHBYTES)
801 				(void) putchar('#');
802 			(void) putchar('\n');
803 			(void) fflush(stdout);
804 		}
805 		if (c < 0) {
806 			if (errno != EPIPE)
807 				perror("netin");
808 			bytes = -1;
809 		}
810 		if (d < c) {
811 			if (d < 0)
812 				perror(local);
813 			else
814 				fprintf(stderr, "%s: short write\n", local);
815 		}
816 		break;
817 
818 	case TYPE_A:
819 		while ((c = getc(din)) != EOF) {
820 			while (c == '\r') {
821 				while (hash && (bytes >= hashbytes)) {
822 					(void) putchar('#');
823 					(void) fflush(stdout);
824 					hashbytes += HASHBYTES;
825 				}
826 				bytes++;
827 				if ((c = getc(din)) != '\n' || tcrflag) {
828 					if (ferror(fout))
829 						goto break2;
830 					(void) putc('\r', fout);
831 					if (c == '\0') {
832 						bytes++;
833 						goto contin2;
834 					}
835 					if (c == EOF)
836 						goto contin2;
837 				}
838 			}
839 			(void) putc(c, fout);
840 			bytes++;
841 	contin2:	;
842 		}
843 break2:
844 		if (hash) {
845 			if (bytes < hashbytes)
846 				(void) putchar('#');
847 			(void) putchar('\n');
848 			(void) fflush(stdout);
849 		}
850 		if (ferror(din)) {
851 			if (errno != EPIPE)
852 				perror("netin");
853 			bytes = -1;
854 		}
855 		if (ferror(fout))
856 			perror(local);
857 		break;
858 	}
859 	if (closefunc != NULL)
860 		(*closefunc)(fout);
861 	(void) signal(SIGINT, oldintr);
862 	if (oldintp)
863 		(void) signal(SIGPIPE, oldintp);
864 	(void) gettimeofday(&stop, (struct timezone *)0);
865 	(void) fclose(din);
866 	(void) getreply(0);
867 	if (bytes > 0 && is_retr)
868 		ptransfer("received", bytes, &start, &stop, local, remote);
869 	if (oldtype) {
870 		if (!debug)
871 			verbose = 0;
872 		switch (oldtype) {
873 			case TYPE_I:
874 				setbinary();
875 				break;
876 			case TYPE_E:
877 				setebcdic();
878 				break;
879 			case TYPE_L:
880 				settenex();
881 				break;
882 		}
883 		verbose = oldverbose;
884 	}
885 	return;
886 abort:
887 
888 /* abort using RFC959 recommended IP,SYNC sequence  */
889 
890 	(void) gettimeofday(&stop, (struct timezone *)0);
891 	if (oldintp)
892 		(void) signal(SIGPIPE, oldintr);
893 	(void) signal(SIGINT,SIG_IGN);
894 	if (oldtype) {
895 		if (!debug)
896 			verbose = 0;
897 		switch (oldtype) {
898 			case TYPE_I:
899 				setbinary();
900 				break;
901 			case TYPE_E:
902 				setebcdic();
903 				break;
904 			case TYPE_L:
905 				settenex();
906 				break;
907 		}
908 		verbose = oldverbose;
909 	}
910 	if (!cpend) {
911 		code = -1;
912 		(void) signal(SIGINT,oldintr);
913 		return;
914 	}
915 
916 	fprintf(cout,"%c%c",IAC,IP);
917 	(void) fflush(cout);
918 	msg = IAC;
919 /* send IAC in urgent mode instead of DM because UNIX places oob mark */
920 /* after urgent byte rather than before as now is protocol            */
921 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
922 		perror("abort");
923 	}
924 	fprintf(cout,"%cABOR\r\n",DM);
925 	(void) fflush(cout);
926 	FD_ZERO(&mask);
927 	FD_SET(fileno(cin), &mask);
928 	if (din) {
929 		FD_SET(fileno(din), &mask);
930 	}
931 	if ((nfnd = empty(&mask,10)) <= 0) {
932 		if (nfnd < 0) {
933 			perror("abort");
934 		}
935 		code = -1;
936 		lostpeer();
937 	}
938 	if (din && FD_ISSET(fileno(din), &mask)) {
939 		while ((c = read(fileno(din), buf, bufsize)) > 0)
940 			;
941 	}
942 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
943 		if (data >= 0) {
944 			(void) close(data);
945 			data = -1;
946 		}
947 		(void) getreply(0);
948 	}
949 	(void) getreply(0);
950 	code = -1;
951 	if (data >= 0) {
952 		(void) close(data);
953 		data = -1;
954 	}
955 	if (closefunc != NULL && fout != NULL)
956 		(*closefunc)(fout);
957 	if (din)
958 		(void) fclose(din);
959 	if (bytes > 0)
960 		ptransfer("received", bytes, &start, &stop, local, remote);
961 	(void) signal(SIGINT,oldintr);
962 }
963 
964 /*
965  * Need to start a listen on the data channel
966  * before we send the command, otherwise the
967  * server's connect may fail.
968  */
969 int sendport = -1;
970 
971 initconn()
972 {
973 	register char *p, *a;
974 	int result, len, tmpno = 0;
975 	int on = 1;
976 
977 noport:
978 	data_addr = myctladdr;
979 	if (sendport)
980 		data_addr.sin_port = 0;	/* let system pick one */
981 	if (data != -1)
982 		(void) close (data);
983 	data = socket(AF_INET, SOCK_STREAM, 0);
984 	if (data < 0) {
985 		perror("ftp: socket");
986 		if (tmpno)
987 			sendport = 1;
988 		return (1);
989 	}
990 	if (!sendport)
991 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
992 			perror("ftp: setsockopt (reuse address)");
993 			goto bad;
994 		}
995 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
996 		perror("ftp: bind");
997 		goto bad;
998 	}
999 	if (options & SO_DEBUG &&
1000 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
1001 		perror("ftp: setsockopt (ignored)");
1002 	len = sizeof (data_addr);
1003 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
1004 		perror("ftp: getsockname");
1005 		goto bad;
1006 	}
1007 	if (listen(data, 1) < 0)
1008 		perror("ftp: listen");
1009 	if (sendport) {
1010 		a = (char *)&data_addr.sin_addr;
1011 		p = (char *)&data_addr.sin_port;
1012 #define	UC(b)	(((int)b)&0xff)
1013 		result =
1014 		    command("PORT %d,%d,%d,%d,%d,%d",
1015 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1016 		      UC(p[0]), UC(p[1]));
1017 		if (result == ERROR && sendport == -1) {
1018 			sendport = 0;
1019 			tmpno = 1;
1020 			goto noport;
1021 		}
1022 		return (result != COMPLETE);
1023 	}
1024 	if (tmpno)
1025 		sendport = 1;
1026 	return (0);
1027 bad:
1028 	(void) close(data), data = -1;
1029 	if (tmpno)
1030 		sendport = 1;
1031 	return (1);
1032 }
1033 
1034 FILE *
1035 dataconn(mode)
1036 	char *mode;
1037 {
1038 	struct sockaddr_in from;
1039 	int s, fromlen = sizeof (from);
1040 
1041 	s = accept(data, (struct sockaddr *) &from, &fromlen);
1042 	if (s < 0) {
1043 		perror("ftp: accept");
1044 		(void) close(data), data = -1;
1045 		return (NULL);
1046 	}
1047 	(void) close(data);
1048 	data = s;
1049 	return (fdopen(data, mode));
1050 }
1051 
1052 ptransfer(direction, bytes, t0, t1, local, remote)
1053 	char *direction, *local, *remote;
1054 	long bytes;
1055 	struct timeval *t0, *t1;
1056 {
1057 	struct timeval td;
1058 	float s, bs;
1059 
1060 	if (verbose) {
1061 		tvsub(&td, t1, t0);
1062 		s = td.tv_sec + (td.tv_usec / 1000000.);
1063 #define	nz(x)	((x) == 0 ? 1 : (x))
1064 		bs = bytes / nz(s);
1065 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
1066 		    bytes, direction, s, bs / 1024.);
1067 	} else {
1068 		if (local && *local != '-')
1069 			printf("local: %s ", local);
1070 		if (remote)
1071 			printf("remote: %s\n", remote);
1072 	}
1073 }
1074 
1075 /*tvadd(tsum, t0)
1076 	struct timeval *tsum, *t0;
1077 {
1078 
1079 	tsum->tv_sec += t0->tv_sec;
1080 	tsum->tv_usec += t0->tv_usec;
1081 	if (tsum->tv_usec > 1000000)
1082 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
1083 } */
1084 
1085 tvsub(tdiff, t1, t0)
1086 	struct timeval *tdiff, *t1, *t0;
1087 {
1088 
1089 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
1090 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
1091 	if (tdiff->tv_usec < 0)
1092 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
1093 }
1094 
1095 psabort()
1096 {
1097 	extern int abrtflag;
1098 
1099 	abrtflag++;
1100 }
1101 
1102 pswitch(flag)
1103 	int flag;
1104 {
1105 	extern int proxy, abrtflag;
1106 	int (*oldintr)();
1107 	static struct comvars {
1108 		int connect;
1109 		char name[MAXHOSTNAMELEN];
1110 		struct sockaddr_in mctl;
1111 		struct sockaddr_in hctl;
1112 		FILE *in;
1113 		FILE *out;
1114 		int tpe;
1115 		int cpnd;
1116 		int sunqe;
1117 		int runqe;
1118 		int mcse;
1119 		int ntflg;
1120 		char nti[17];
1121 		char nto[17];
1122 		int mapflg;
1123 		char mi[MAXPATHLEN];
1124 		char mo[MAXPATHLEN];
1125 		} proxstruct, tmpstruct;
1126 	struct comvars *ip, *op;
1127 
1128 	abrtflag = 0;
1129 	oldintr = signal(SIGINT, psabort);
1130 	if (flag) {
1131 		if (proxy)
1132 			return;
1133 		ip = &tmpstruct;
1134 		op = &proxstruct;
1135 		proxy++;
1136 	}
1137 	else {
1138 		if (!proxy)
1139 			return;
1140 		ip = &proxstruct;
1141 		op = &tmpstruct;
1142 		proxy = 0;
1143 	}
1144 	ip->connect = connected;
1145 	connected = op->connect;
1146 	if (hostname) {
1147 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1148 		ip->name[strlen(ip->name)] = '\0';
1149 	} else
1150 		ip->name[0] = 0;
1151 	hostname = op->name;
1152 	ip->hctl = hisctladdr;
1153 	hisctladdr = op->hctl;
1154 	ip->mctl = myctladdr;
1155 	myctladdr = op->mctl;
1156 	ip->in = cin;
1157 	cin = op->in;
1158 	ip->out = cout;
1159 	cout = op->out;
1160 	ip->tpe = type;
1161 	type = op->tpe;
1162 	if (!type)
1163 		type = 1;
1164 	ip->cpnd = cpend;
1165 	cpend = op->cpnd;
1166 	ip->sunqe = sunique;
1167 	sunique = op->sunqe;
1168 	ip->runqe = runique;
1169 	runique = op->runqe;
1170 	ip->mcse = mcase;
1171 	mcase = op->mcse;
1172 	ip->ntflg = ntflag;
1173 	ntflag = op->ntflg;
1174 	(void) strncpy(ip->nti, ntin, 16);
1175 	(ip->nti)[strlen(ip->nti)] = '\0';
1176 	(void) strcpy(ntin, op->nti);
1177 	(void) strncpy(ip->nto, ntout, 16);
1178 	(ip->nto)[strlen(ip->nto)] = '\0';
1179 	(void) strcpy(ntout, op->nto);
1180 	ip->mapflg = mapflag;
1181 	mapflag = op->mapflg;
1182 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
1183 	(ip->mi)[strlen(ip->mi)] = '\0';
1184 	(void) strcpy(mapin, op->mi);
1185 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
1186 	(ip->mo)[strlen(ip->mo)] = '\0';
1187 	(void) strcpy(mapout, op->mo);
1188 	(void) signal(SIGINT, oldintr);
1189 	if (abrtflag) {
1190 		abrtflag = 0;
1191 		(*oldintr)();
1192 	}
1193 }
1194 
1195 jmp_buf ptabort;
1196 int ptabflg;
1197 
1198 abortpt()
1199 {
1200 	printf("\n");
1201 	(void) fflush(stdout);
1202 	ptabflg++;
1203 	mflag = 0;
1204 	abrtflag = 0;
1205 	longjmp(ptabort, 1);
1206 }
1207 
1208 proxtrans(cmd, local, remote)
1209 	char *cmd, *local, *remote;
1210 {
1211 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
1212 	extern jmp_buf ptabort;
1213 	char *cmd2;
1214 	struct fd_set mask;
1215 
1216 	if (strcmp(cmd, "RETR"))
1217 		cmd2 = "RETR";
1218 	else
1219 		cmd2 = runique ? "STOU" : "STOR";
1220 	if (command("PASV") != COMPLETE) {
1221 		printf("proxy server does not support third part transfers.\n");
1222 		return;
1223 	}
1224 	tmptype = type;
1225 	pswitch(0);
1226 	if (!connected) {
1227 		printf("No primary connection\n");
1228 		pswitch(1);
1229 		code = -1;
1230 		return;
1231 	}
1232 	if (type != tmptype) {
1233 		oldtype = type;
1234 		switch (tmptype) {
1235 			case TYPE_A:
1236 				setascii();
1237 				break;
1238 			case TYPE_I:
1239 				setbinary();
1240 				break;
1241 			case TYPE_E:
1242 				setebcdic();
1243 				break;
1244 			case TYPE_L:
1245 				settenex();
1246 				break;
1247 		}
1248 	}
1249 	if (command("PORT %s", pasv) != COMPLETE) {
1250 		switch (oldtype) {
1251 			case 0:
1252 				break;
1253 			case TYPE_A:
1254 				setascii();
1255 				break;
1256 			case TYPE_I:
1257 				setbinary();
1258 				break;
1259 			case TYPE_E:
1260 				setebcdic();
1261 				break;
1262 			case TYPE_L:
1263 				settenex();
1264 				break;
1265 		}
1266 		pswitch(1);
1267 		return;
1268 	}
1269 	if (setjmp(ptabort))
1270 		goto abort;
1271 	oldintr = signal(SIGINT, abortpt);
1272 	if (command("%s %s", cmd, remote) != PRELIM) {
1273 		(void) signal(SIGINT, oldintr);
1274 		switch (oldtype) {
1275 			case 0:
1276 				break;
1277 			case TYPE_A:
1278 				setascii();
1279 				break;
1280 			case TYPE_I:
1281 				setbinary();
1282 				break;
1283 			case TYPE_E:
1284 				setebcdic();
1285 				break;
1286 			case TYPE_L:
1287 				settenex();
1288 				break;
1289 		}
1290 		pswitch(1);
1291 		return;
1292 	}
1293 	sleep(2);
1294 	pswitch(1);
1295 	secndflag++;
1296 	if (command("%s %s", cmd2, local) != PRELIM)
1297 		goto abort;
1298 	ptflag++;
1299 	(void) getreply(0);
1300 	pswitch(0);
1301 	(void) getreply(0);
1302 	(void) signal(SIGINT, oldintr);
1303 	switch (oldtype) {
1304 		case 0:
1305 			break;
1306 		case TYPE_A:
1307 			setascii();
1308 			break;
1309 		case TYPE_I:
1310 			setbinary();
1311 			break;
1312 		case TYPE_E:
1313 			setebcdic();
1314 			break;
1315 		case TYPE_L:
1316 			settenex();
1317 			break;
1318 	}
1319 	pswitch(1);
1320 	ptflag = 0;
1321 	printf("local: %s remote: %s\n", local, remote);
1322 	return;
1323 abort:
1324 	(void) signal(SIGINT, SIG_IGN);
1325 	ptflag = 0;
1326 	if (strcmp(cmd, "RETR") && !proxy)
1327 		pswitch(1);
1328 	else if (!strcmp(cmd, "RETR") && proxy)
1329 		pswitch(0);
1330 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1331 		if (command("%s %s", cmd2, local) != PRELIM) {
1332 			pswitch(0);
1333 			switch (oldtype) {
1334 				case 0:
1335 					break;
1336 				case TYPE_A:
1337 					setascii();
1338 					break;
1339 				case TYPE_I:
1340 					setbinary();
1341 					break;
1342 				case TYPE_E:
1343 					setebcdic();
1344 					break;
1345 				case TYPE_L:
1346 					settenex();
1347 					break;
1348 			}
1349 			if (cpend) {
1350 				char msg[2];
1351 
1352 				fprintf(cout,"%c%c",IAC,IP);
1353 				(void) fflush(cout);
1354 				*msg = IAC;
1355 				*(msg+1) = DM;
1356 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1357 					perror("abort");
1358 				fprintf(cout,"ABOR\r\n");
1359 				(void) fflush(cout);
1360 				FD_ZERO(&mask);
1361 				FD_SET(fileno(cin), &mask);
1362 				if ((nfnd = empty(&mask,10)) <= 0) {
1363 					if (nfnd < 0) {
1364 						perror("abort");
1365 					}
1366 					if (ptabflg)
1367 						code = -1;
1368 					lostpeer();
1369 				}
1370 				(void) getreply(0);
1371 				(void) getreply(0);
1372 			}
1373 		}
1374 		pswitch(1);
1375 		if (ptabflg)
1376 			code = -1;
1377 		(void) signal(SIGINT, oldintr);
1378 		return;
1379 	}
1380 	if (cpend) {
1381 		char msg[2];
1382 
1383 		fprintf(cout,"%c%c",IAC,IP);
1384 		(void) fflush(cout);
1385 		*msg = IAC;
1386 		*(msg+1) = DM;
1387 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1388 			perror("abort");
1389 		fprintf(cout,"ABOR\r\n");
1390 		(void) fflush(cout);
1391 		FD_ZERO(&mask);
1392 		FD_SET(fileno(cin), &mask);
1393 		if ((nfnd = empty(&mask,10)) <= 0) {
1394 			if (nfnd < 0) {
1395 				perror("abort");
1396 			}
1397 			if (ptabflg)
1398 				code = -1;
1399 			lostpeer();
1400 		}
1401 		(void) getreply(0);
1402 		(void) getreply(0);
1403 	}
1404 	pswitch(!proxy);
1405 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1406 		if (command("%s %s", cmd2, local) != PRELIM) {
1407 			pswitch(0);
1408 			switch (oldtype) {
1409 				case 0:
1410 					break;
1411 				case TYPE_A:
1412 					setascii();
1413 					break;
1414 				case TYPE_I:
1415 					setbinary();
1416 					break;
1417 				case TYPE_E:
1418 					setebcdic();
1419 					break;
1420 				case TYPE_L:
1421 					settenex();
1422 					break;
1423 			}
1424 			if (cpend) {
1425 				char msg[2];
1426 
1427 				fprintf(cout,"%c%c",IAC,IP);
1428 				(void) fflush(cout);
1429 				*msg = IAC;
1430 				*(msg+1) = DM;
1431 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1432 					perror("abort");
1433 				fprintf(cout,"ABOR\r\n");
1434 				(void) fflush(cout);
1435 				FD_ZERO(&mask);
1436 				FD_SET(fileno(cin), &mask);
1437 				if ((nfnd = empty(&mask,10)) <= 0) {
1438 					if (nfnd < 0) {
1439 						perror("abort");
1440 					}
1441 					if (ptabflg)
1442 						code = -1;
1443 					lostpeer();
1444 				}
1445 				(void) getreply(0);
1446 				(void) getreply(0);
1447 			}
1448 			pswitch(1);
1449 			if (ptabflg)
1450 				code = -1;
1451 			(void) signal(SIGINT, oldintr);
1452 			return;
1453 		}
1454 	}
1455 	if (cpend) {
1456 		char msg[2];
1457 
1458 		fprintf(cout,"%c%c",IAC,IP);
1459 		(void) fflush(cout);
1460 		*msg = IAC;
1461 		*(msg+1) = DM;
1462 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1463 			perror("abort");
1464 		fprintf(cout,"ABOR\r\n");
1465 		(void) fflush(cout);
1466 		FD_ZERO(&mask);
1467 		FD_SET(fileno(cin), &mask);
1468 		if ((nfnd = empty(&mask,10)) <= 0) {
1469 			if (nfnd < 0) {
1470 				perror("abort");
1471 			}
1472 			if (ptabflg)
1473 				code = -1;
1474 			lostpeer();
1475 		}
1476 		(void) getreply(0);
1477 		(void) getreply(0);
1478 	}
1479 	pswitch(!proxy);
1480 	if (cpend) {
1481 		FD_ZERO(&mask);
1482 		FD_SET(fileno(cin), &mask);
1483 		if ((nfnd = empty(&mask,10)) <= 0) {
1484 			if (nfnd < 0) {
1485 				perror("abort");
1486 			}
1487 			if (ptabflg)
1488 				code = -1;
1489 			lostpeer();
1490 		}
1491 		(void) getreply(0);
1492 		(void) getreply(0);
1493 	}
1494 	if (proxy)
1495 		pswitch(0);
1496 	switch (oldtype) {
1497 		case 0:
1498 			break;
1499 		case TYPE_A:
1500 			setascii();
1501 			break;
1502 		case TYPE_I:
1503 			setbinary();
1504 			break;
1505 		case TYPE_E:
1506 			setebcdic();
1507 			break;
1508 		case TYPE_L:
1509 			settenex();
1510 			break;
1511 	}
1512 	pswitch(1);
1513 	if (ptabflg)
1514 		code = -1;
1515 	(void) signal(SIGINT, oldintr);
1516 }
1517 
1518 reset()
1519 {
1520 	struct fd_set mask;
1521 	int nfnd = 1;
1522 
1523 	FD_ZERO(&mask);
1524 	while (nfnd > 0) {
1525 		FD_SET(fileno(cin), &mask);
1526 		if ((nfnd = empty(&mask,0)) < 0) {
1527 			perror("reset");
1528 			code = -1;
1529 			lostpeer();
1530 		}
1531 		else if (nfnd) {
1532 			(void) getreply(0);
1533 		}
1534 	}
1535 }
1536 
1537 char *
1538 gunique(local)
1539 	char *local;
1540 {
1541 	static char new[MAXPATHLEN];
1542 	char *cp = rindex(local, '/');
1543 	int d, count=0;
1544 	char ext = '1';
1545 
1546 	if (cp)
1547 		*cp = '\0';
1548 	d = access(cp ? local : ".", 2);
1549 	if (cp)
1550 		*cp = '/';
1551 	if (d < 0) {
1552 		perror(local);
1553 		return((char *) 0);
1554 	}
1555 	(void) strcpy(new, local);
1556 	cp = new + strlen(new);
1557 	*cp++ = '.';
1558 	while (!d) {
1559 		if (++count == 100) {
1560 			printf("runique: can't find unique file name.\n");
1561 			return((char *) 0);
1562 		}
1563 		*cp++ = ext;
1564 		*cp = '\0';
1565 		if (ext == '9')
1566 			ext = '0';
1567 		else
1568 			ext++;
1569 		if ((d = access(new, 0)) < 0)
1570 			break;
1571 		if (ext != '0')
1572 			cp--;
1573 		else if (*(cp - 2) == '.')
1574 			*(cp - 1) = '1';
1575 		else {
1576 			*(cp - 2) = *(cp - 2) + 1;
1577 			cp--;
1578 		}
1579 	}
1580 	return(new);
1581 }
1582