xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 36943)
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.2 (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 *buf, *bufp, *gunique(), msg;
614 	static int bufsize;
615 	long bytes = 0, hashbytes = HASHBYTES;
616 	struct fd_set mask;
617 	register int c, d;
618 	struct timeval start, stop;
619 	struct stat st;
620 	extern char *malloc();
621 
622 	is_retr = strcmp(cmd, "RETR") == 0;
623 	if (proxy && is_retr) {
624 		proxtrans(cmd, local, remote);
625 		return;
626 	}
627 	closefunc = NULL;
628 	oldintr = NULL;
629 	oldintp = NULL;
630 	tcrflag = !crflag && is_retr;
631 	if (setjmp(recvabort)) {
632 		while (cpend) {
633 			(void) getreply(0);
634 		}
635 		if (data >= 0) {
636 			(void) close(data);
637 			data = -1;
638 		}
639 		if (oldintr)
640 			(void) signal(SIGINT, oldintr);
641 		code = -1;
642 		return;
643 	}
644 	oldintr = signal(SIGINT, abortrecv);
645 	if (strcmp(local, "-") && *local != '|') {
646 		if (access(local, 2) < 0) {
647 			char *dir = rindex(local, '/');
648 
649 			if (errno != ENOENT && errno != EACCES) {
650 				perror(local);
651 				(void) signal(SIGINT, oldintr);
652 				code = -1;
653 				return;
654 			}
655 			if (dir != NULL)
656 				*dir = 0;
657 			d = access(dir ? local : ".", 2);
658 			if (dir != NULL)
659 				*dir = '/';
660 			if (d < 0) {
661 				perror(local);
662 				(void) signal(SIGINT, oldintr);
663 				code = -1;
664 				return;
665 			}
666 			if (!runique && errno == EACCES &&
667 			    chmod(local, 0600) < 0) {
668 				perror(local);
669 				(void) signal(SIGINT, oldintr);
670 				code = -1;
671 				return;
672 			}
673 			if (runique && errno == EACCES &&
674 			   (local = gunique(local)) == NULL) {
675 				(void) signal(SIGINT, oldintr);
676 				code = -1;
677 				return;
678 			}
679 		}
680 		else if (runique && (local = gunique(local)) == NULL) {
681 			(void) signal(SIGINT, oldintr);
682 			code = -1;
683 			return;
684 		}
685 	}
686 	if (initconn()) {
687 		(void) signal(SIGINT, oldintr);
688 		code = -1;
689 		return;
690 	}
691 	if (setjmp(recvabort))
692 		goto abort;
693 	if (!is_retr) {
694 		if (type != TYPE_A) {
695 			oldtype = type;
696 			oldverbose = verbose;
697 			if (!debug)
698 				verbose = 0;
699 			setascii();
700 			verbose = oldverbose;
701 		}
702 	}
703 	if (remote) {
704 		if (command("%s %s", cmd, remote) != PRELIM) {
705 			(void) signal(SIGINT, oldintr);
706 			if (oldtype) {
707 				if (!debug)
708 					verbose = 0;
709 				switch (oldtype) {
710 					case TYPE_I:
711 						setbinary();
712 						break;
713 					case TYPE_E:
714 						setebcdic();
715 						break;
716 					case TYPE_L:
717 						settenex();
718 						break;
719 				}
720 				verbose = oldverbose;
721 			}
722 			return;
723 		}
724 	} else {
725 		if (command("%s", cmd) != PRELIM) {
726 			(void) signal(SIGINT, oldintr);
727 			if (oldtype) {
728 				if (!debug)
729 					verbose = 0;
730 				switch (oldtype) {
731 					case TYPE_I:
732 						setbinary();
733 						break;
734 					case TYPE_E:
735 						setebcdic();
736 						break;
737 					case TYPE_L:
738 						settenex();
739 						break;
740 				}
741 				verbose = oldverbose;
742 			}
743 			return;
744 		}
745 	}
746 	din = dataconn("r");
747 	if (din == NULL)
748 		goto abort;
749 	if (strcmp(local, "-") == 0)
750 		fout = stdout;
751 	else if (*local == '|') {
752 		oldintp = signal(SIGPIPE, SIG_IGN);
753 		fout = popen(local + 1, "w");
754 		if (fout == NULL) {
755 			perror(local+1);
756 			goto abort;
757 		}
758 		closefunc = pclose;
759 	} else {
760 		fout = fopen(local, mode);
761 		if (fout == NULL) {
762 			perror(local);
763 			goto abort;
764 		}
765 		closefunc = fclose;
766 	}
767 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
768 		st.st_blksize = BUFSIZ;
769 	if (st.st_blksize > bufsize) {
770 		if (buf)
771 			(void) free(buf);
772 		buf = malloc(st.st_blksize);
773 		if (buf == NULL) {
774 			perror("malloc");
775 			goto abort;
776 		}
777 		bufsize = st.st_blksize;
778 	}
779 	(void) gettimeofday(&start, (struct timezone *)0);
780 	switch (type) {
781 
782 	case TYPE_I:
783 	case TYPE_L:
784 		errno = d = 0;
785 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
786 			if ((d = write(fileno(fout), bufp, c)) != c)
787 				break;
788 			bytes += c;
789 			if (hash) {
790 				while (bytes >= hashbytes) {
791 					(void) putchar('#');
792 					hashbytes += HASHBYTES;
793 				}
794 				(void) fflush(stdout);
795 			}
796 		}
797 		if (hash && bytes > 0) {
798 			if (bytes < HASHBYTES)
799 				(void) putchar('#');
800 			(void) putchar('\n');
801 			(void) fflush(stdout);
802 		}
803 		if (c < 0) {
804 			if (errno != EPIPE)
805 				perror("netin");
806 			bytes = -1;
807 		}
808 		if (d < c) {
809 			if (d < 0)
810 				perror(local);
811 			else
812 				fprintf(stderr, "%s: short write\n", local);
813 		}
814 		break;
815 
816 	case TYPE_A:
817 		while ((c = getc(din)) != EOF) {
818 			while (c == '\r') {
819 				while (hash && (bytes >= hashbytes)) {
820 					(void) putchar('#');
821 					(void) fflush(stdout);
822 					hashbytes += HASHBYTES;
823 				}
824 				bytes++;
825 				if ((c = getc(din)) != '\n' || tcrflag) {
826 					if (ferror(fout))
827 						goto break2;
828 					(void) putc('\r', fout);
829 					if (c == '\0') {
830 						bytes++;
831 						goto contin2;
832 					}
833 					if (c == EOF)
834 						goto contin2;
835 				}
836 			}
837 			(void) putc(c, fout);
838 			bytes++;
839 	contin2:	;
840 		}
841 break2:
842 		if (hash) {
843 			if (bytes < hashbytes)
844 				(void) putchar('#');
845 			(void) putchar('\n');
846 			(void) fflush(stdout);
847 		}
848 		if (ferror(din)){
849 			if (errno != EPIPE)
850 				perror ("netin");
851 			bytes = -1;
852 		}
853 		if (ferror(fout))
854 			perror (local);
855 		break;
856 	}
857 	if (closefunc != NULL)
858 		(*closefunc)(fout);
859 	(void) signal(SIGINT, oldintr);
860 	if (oldintp)
861 		(void) signal(SIGPIPE, oldintp);
862 	(void) gettimeofday(&stop, (struct timezone *)0);
863 	(void) fclose(din);
864 	(void) getreply(0);
865 	if (bytes > 0 && is_retr)
866 		ptransfer("received", bytes, &start, &stop, local, remote);
867 	if (oldtype) {
868 		if (!debug)
869 			verbose = 0;
870 		switch (oldtype) {
871 			case TYPE_I:
872 				setbinary();
873 				break;
874 			case TYPE_E:
875 				setebcdic();
876 				break;
877 			case TYPE_L:
878 				settenex();
879 				break;
880 		}
881 		verbose = oldverbose;
882 	}
883 	return;
884 abort:
885 
886 /* abort using RFC959 recommended IP,SYNC sequence  */
887 
888 	(void) gettimeofday(&stop, (struct timezone *)0);
889 	if (oldintp)
890 		(void) signal(SIGPIPE, oldintr);
891 	(void) signal(SIGINT,SIG_IGN);
892 	if (oldtype) {
893 		if (!debug)
894 			verbose = 0;
895 		switch (oldtype) {
896 			case TYPE_I:
897 				setbinary();
898 				break;
899 			case TYPE_E:
900 				setebcdic();
901 				break;
902 			case TYPE_L:
903 				settenex();
904 				break;
905 		}
906 		verbose = oldverbose;
907 	}
908 	if (!cpend) {
909 		code = -1;
910 		(void) signal(SIGINT,oldintr);
911 		return;
912 	}
913 
914 	fprintf(cout,"%c%c",IAC,IP);
915 	(void) fflush(cout);
916 	msg = IAC;
917 /* send IAC in urgent mode instead of DM because UNIX places oob mark */
918 /* after urgent byte rather than before as now is protocol            */
919 	if (send(fileno(cout),&msg,1,MSG_OOB) != 1) {
920 		perror("abort");
921 	}
922 	fprintf(cout,"%cABOR\r\n",DM);
923 	(void) fflush(cout);
924 	FD_ZERO(&mask);
925 	FD_SET(fileno(cin), &mask);
926 	if (din) {
927 		FD_SET(fileno(din), &mask);
928 	}
929 	if ((nfnd = empty(&mask,10)) <= 0) {
930 		if (nfnd < 0) {
931 			perror("abort");
932 		}
933 		code = -1;
934 		lostpeer();
935 	}
936 	if (din && FD_ISSET(fileno(din), &mask)) {
937 		while ((c = read(fileno(din), buf, bufsize)) > 0)
938 			;
939 	}
940 	if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */
941 		if (data >= 0) {
942 			(void) close(data);
943 			data = -1;
944 		}
945 		(void) getreply(0);
946 	}
947 	(void) getreply(0);
948 	code = -1;
949 	if (data >= 0) {
950 		(void) close(data);
951 		data = -1;
952 	}
953 	if (closefunc != NULL && fout != NULL)
954 		(*closefunc)(fout);
955 	if (din)
956 		(void) fclose(din);
957 	if (bytes > 0)
958 		ptransfer("received", bytes, &start, &stop, local, remote);
959 	(void) signal(SIGINT,oldintr);
960 }
961 
962 /*
963  * Need to start a listen on the data channel
964  * before we send the command, otherwise the
965  * server's connect may fail.
966  */
967 int sendport = -1;
968 
969 initconn()
970 {
971 	register char *p, *a;
972 	int result, len, tmpno = 0;
973 	int on = 1;
974 
975 noport:
976 	data_addr = myctladdr;
977 	if (sendport)
978 		data_addr.sin_port = 0;	/* let system pick one */
979 	if (data != -1)
980 		(void) close (data);
981 	data = socket(AF_INET, SOCK_STREAM, 0);
982 	if (data < 0) {
983 		perror("ftp: socket");
984 		if (tmpno)
985 			sendport = 1;
986 		return (1);
987 	}
988 	if (!sendport)
989 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
990 			perror("ftp: setsockopt (reuse address)");
991 			goto bad;
992 		}
993 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
994 		perror("ftp: bind");
995 		goto bad;
996 	}
997 	if (options & SO_DEBUG &&
998 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
999 		perror("ftp: setsockopt (ignored)");
1000 	len = sizeof (data_addr);
1001 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
1002 		perror("ftp: getsockname");
1003 		goto bad;
1004 	}
1005 	if (listen(data, 1) < 0)
1006 		perror("ftp: listen");
1007 	if (sendport) {
1008 		a = (char *)&data_addr.sin_addr;
1009 		p = (char *)&data_addr.sin_port;
1010 #define	UC(b)	(((int)b)&0xff)
1011 		result =
1012 		    command("PORT %d,%d,%d,%d,%d,%d",
1013 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1014 		      UC(p[0]), UC(p[1]));
1015 		if (result == ERROR && sendport == -1) {
1016 			sendport = 0;
1017 			tmpno = 1;
1018 			goto noport;
1019 		}
1020 		return (result != COMPLETE);
1021 	}
1022 	if (tmpno)
1023 		sendport = 1;
1024 	return (0);
1025 bad:
1026 	(void) close(data), data = -1;
1027 	if (tmpno)
1028 		sendport = 1;
1029 	return (1);
1030 }
1031 
1032 FILE *
1033 dataconn(mode)
1034 	char *mode;
1035 {
1036 	struct sockaddr_in from;
1037 	int s, fromlen = sizeof (from);
1038 
1039 	s = accept(data, (struct sockaddr *) &from, &fromlen);
1040 	if (s < 0) {
1041 		perror("ftp: accept");
1042 		(void) close(data), data = -1;
1043 		return (NULL);
1044 	}
1045 	(void) close(data);
1046 	data = s;
1047 	return (fdopen(data, mode));
1048 }
1049 
1050 ptransfer(direction, bytes, t0, t1, local, remote)
1051 	char *direction, *local, *remote;
1052 	long bytes;
1053 	struct timeval *t0, *t1;
1054 {
1055 	struct timeval td;
1056 	float s, bs;
1057 
1058 	if (verbose) {
1059 		tvsub(&td, t1, t0);
1060 		s = td.tv_sec + (td.tv_usec / 1000000.);
1061 #define	nz(x)	((x) == 0 ? 1 : (x))
1062 		bs = bytes / nz(s);
1063 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
1064 		    bytes, direction, s, bs / 1024.);
1065 	} else {
1066 		if (local && *local != '-')
1067 			printf("local: %s ", local);
1068 		if (remote)
1069 			printf("remote: %s\n", remote);
1070 	}
1071 }
1072 
1073 /*tvadd(tsum, t0)
1074 	struct timeval *tsum, *t0;
1075 {
1076 
1077 	tsum->tv_sec += t0->tv_sec;
1078 	tsum->tv_usec += t0->tv_usec;
1079 	if (tsum->tv_usec > 1000000)
1080 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
1081 } */
1082 
1083 tvsub(tdiff, t1, t0)
1084 	struct timeval *tdiff, *t1, *t0;
1085 {
1086 
1087 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
1088 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
1089 	if (tdiff->tv_usec < 0)
1090 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
1091 }
1092 
1093 psabort()
1094 {
1095 	extern int abrtflag;
1096 
1097 	abrtflag++;
1098 }
1099 
1100 pswitch(flag)
1101 	int flag;
1102 {
1103 	extern int proxy, abrtflag;
1104 	int (*oldintr)();
1105 	static struct comvars {
1106 		int connect;
1107 		char name[MAXHOSTNAMELEN];
1108 		struct sockaddr_in mctl;
1109 		struct sockaddr_in hctl;
1110 		FILE *in;
1111 		FILE *out;
1112 		int tpe;
1113 		int cpnd;
1114 		int sunqe;
1115 		int runqe;
1116 		int mcse;
1117 		int ntflg;
1118 		char nti[17];
1119 		char nto[17];
1120 		int mapflg;
1121 		char mi[MAXPATHLEN];
1122 		char mo[MAXPATHLEN];
1123 		} proxstruct, tmpstruct;
1124 	struct comvars *ip, *op;
1125 
1126 	abrtflag = 0;
1127 	oldintr = signal(SIGINT, psabort);
1128 	if (flag) {
1129 		if (proxy)
1130 			return;
1131 		ip = &tmpstruct;
1132 		op = &proxstruct;
1133 		proxy++;
1134 	}
1135 	else {
1136 		if (!proxy)
1137 			return;
1138 		ip = &proxstruct;
1139 		op = &tmpstruct;
1140 		proxy = 0;
1141 	}
1142 	ip->connect = connected;
1143 	connected = op->connect;
1144 	if (hostname) {
1145 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1146 		ip->name[strlen(ip->name)] = '\0';
1147 	} else
1148 		ip->name[0] = 0;
1149 	hostname = op->name;
1150 	ip->hctl = hisctladdr;
1151 	hisctladdr = op->hctl;
1152 	ip->mctl = myctladdr;
1153 	myctladdr = op->mctl;
1154 	ip->in = cin;
1155 	cin = op->in;
1156 	ip->out = cout;
1157 	cout = op->out;
1158 	ip->tpe = type;
1159 	type = op->tpe;
1160 	if (!type)
1161 		type = 1;
1162 	ip->cpnd = cpend;
1163 	cpend = op->cpnd;
1164 	ip->sunqe = sunique;
1165 	sunique = op->sunqe;
1166 	ip->runqe = runique;
1167 	runique = op->runqe;
1168 	ip->mcse = mcase;
1169 	mcase = op->mcse;
1170 	ip->ntflg = ntflag;
1171 	ntflag = op->ntflg;
1172 	(void) strncpy(ip->nti, ntin, 16);
1173 	(ip->nti)[strlen(ip->nti)] = '\0';
1174 	(void) strcpy(ntin, op->nti);
1175 	(void) strncpy(ip->nto, ntout, 16);
1176 	(ip->nto)[strlen(ip->nto)] = '\0';
1177 	(void) strcpy(ntout, op->nto);
1178 	ip->mapflg = mapflag;
1179 	mapflag = op->mapflg;
1180 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
1181 	(ip->mi)[strlen(ip->mi)] = '\0';
1182 	(void) strcpy(mapin, op->mi);
1183 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
1184 	(ip->mo)[strlen(ip->mo)] = '\0';
1185 	(void) strcpy(mapout, op->mo);
1186 	(void) signal(SIGINT, oldintr);
1187 	if (abrtflag) {
1188 		abrtflag = 0;
1189 		(*oldintr)();
1190 	}
1191 }
1192 
1193 jmp_buf ptabort;
1194 int ptabflg;
1195 
1196 abortpt()
1197 {
1198 	printf("\n");
1199 	(void) fflush(stdout);
1200 	ptabflg++;
1201 	mflag = 0;
1202 	abrtflag = 0;
1203 	longjmp(ptabort, 1);
1204 }
1205 
1206 proxtrans(cmd, local, remote)
1207 	char *cmd, *local, *remote;
1208 {
1209 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
1210 	extern jmp_buf ptabort;
1211 	char *cmd2;
1212 	struct fd_set mask;
1213 
1214 	if (strcmp(cmd, "RETR"))
1215 		cmd2 = "RETR";
1216 	else
1217 		cmd2 = runique ? "STOU" : "STOR";
1218 	if (command("PASV") != COMPLETE) {
1219 		printf("proxy server does not support third part transfers.\n");
1220 		return;
1221 	}
1222 	tmptype = type;
1223 	pswitch(0);
1224 	if (!connected) {
1225 		printf("No primary connection\n");
1226 		pswitch(1);
1227 		code = -1;
1228 		return;
1229 	}
1230 	if (type != tmptype) {
1231 		oldtype = type;
1232 		switch (tmptype) {
1233 			case TYPE_A:
1234 				setascii();
1235 				break;
1236 			case TYPE_I:
1237 				setbinary();
1238 				break;
1239 			case TYPE_E:
1240 				setebcdic();
1241 				break;
1242 			case TYPE_L:
1243 				settenex();
1244 				break;
1245 		}
1246 	}
1247 	if (command("PORT %s", pasv) != COMPLETE) {
1248 		switch (oldtype) {
1249 			case 0:
1250 				break;
1251 			case TYPE_A:
1252 				setascii();
1253 				break;
1254 			case TYPE_I:
1255 				setbinary();
1256 				break;
1257 			case TYPE_E:
1258 				setebcdic();
1259 				break;
1260 			case TYPE_L:
1261 				settenex();
1262 				break;
1263 		}
1264 		pswitch(1);
1265 		return;
1266 	}
1267 	if (setjmp(ptabort))
1268 		goto abort;
1269 	oldintr = signal(SIGINT, abortpt);
1270 	if (command("%s %s", cmd, remote) != PRELIM) {
1271 		(void) signal(SIGINT, oldintr);
1272 		switch (oldtype) {
1273 			case 0:
1274 				break;
1275 			case TYPE_A:
1276 				setascii();
1277 				break;
1278 			case TYPE_I:
1279 				setbinary();
1280 				break;
1281 			case TYPE_E:
1282 				setebcdic();
1283 				break;
1284 			case TYPE_L:
1285 				settenex();
1286 				break;
1287 		}
1288 		pswitch(1);
1289 		return;
1290 	}
1291 	sleep(2);
1292 	pswitch(1);
1293 	secndflag++;
1294 	if (command("%s %s", cmd2, local) != PRELIM)
1295 		goto abort;
1296 	ptflag++;
1297 	(void) getreply(0);
1298 	pswitch(0);
1299 	(void) getreply(0);
1300 	(void) signal(SIGINT, oldintr);
1301 	switch (oldtype) {
1302 		case 0:
1303 			break;
1304 		case TYPE_A:
1305 			setascii();
1306 			break;
1307 		case TYPE_I:
1308 			setbinary();
1309 			break;
1310 		case TYPE_E:
1311 			setebcdic();
1312 			break;
1313 		case TYPE_L:
1314 			settenex();
1315 			break;
1316 	}
1317 	pswitch(1);
1318 	ptflag = 0;
1319 	printf("local: %s remote: %s\n", local, remote);
1320 	return;
1321 abort:
1322 	(void) signal(SIGINT, SIG_IGN);
1323 	ptflag = 0;
1324 	if (strcmp(cmd, "RETR") && !proxy)
1325 		pswitch(1);
1326 	else if (!strcmp(cmd, "RETR") && proxy)
1327 		pswitch(0);
1328 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1329 		if (command("%s %s", cmd2, local) != PRELIM) {
1330 			pswitch(0);
1331 			switch (oldtype) {
1332 				case 0:
1333 					break;
1334 				case TYPE_A:
1335 					setascii();
1336 					break;
1337 				case TYPE_I:
1338 					setbinary();
1339 					break;
1340 				case TYPE_E:
1341 					setebcdic();
1342 					break;
1343 				case TYPE_L:
1344 					settenex();
1345 					break;
1346 			}
1347 			if (cpend) {
1348 				char msg[2];
1349 
1350 				fprintf(cout,"%c%c",IAC,IP);
1351 				(void) fflush(cout);
1352 				*msg = IAC;
1353 				*(msg+1) = DM;
1354 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1355 					perror("abort");
1356 				fprintf(cout,"ABOR\r\n");
1357 				(void) fflush(cout);
1358 				FD_ZERO(&mask);
1359 				FD_SET(fileno(cin), &mask);
1360 				if ((nfnd = empty(&mask,10)) <= 0) {
1361 					if (nfnd < 0) {
1362 						perror("abort");
1363 					}
1364 					if (ptabflg)
1365 						code = -1;
1366 					lostpeer();
1367 				}
1368 				(void) getreply(0);
1369 				(void) getreply(0);
1370 			}
1371 		}
1372 		pswitch(1);
1373 		if (ptabflg)
1374 			code = -1;
1375 		(void) signal(SIGINT, oldintr);
1376 		return;
1377 	}
1378 	if (cpend) {
1379 		char msg[2];
1380 
1381 		fprintf(cout,"%c%c",IAC,IP);
1382 		(void) fflush(cout);
1383 		*msg = IAC;
1384 		*(msg+1) = DM;
1385 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1386 			perror("abort");
1387 		fprintf(cout,"ABOR\r\n");
1388 		(void) fflush(cout);
1389 		FD_ZERO(&mask);
1390 		FD_SET(fileno(cin), &mask);
1391 		if ((nfnd = empty(&mask,10)) <= 0) {
1392 			if (nfnd < 0) {
1393 				perror("abort");
1394 			}
1395 			if (ptabflg)
1396 				code = -1;
1397 			lostpeer();
1398 		}
1399 		(void) getreply(0);
1400 		(void) getreply(0);
1401 	}
1402 	pswitch(!proxy);
1403 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1404 		if (command("%s %s", cmd2, local) != PRELIM) {
1405 			pswitch(0);
1406 			switch (oldtype) {
1407 				case 0:
1408 					break;
1409 				case TYPE_A:
1410 					setascii();
1411 					break;
1412 				case TYPE_I:
1413 					setbinary();
1414 					break;
1415 				case TYPE_E:
1416 					setebcdic();
1417 					break;
1418 				case TYPE_L:
1419 					settenex();
1420 					break;
1421 			}
1422 			if (cpend) {
1423 				char msg[2];
1424 
1425 				fprintf(cout,"%c%c",IAC,IP);
1426 				(void) fflush(cout);
1427 				*msg = IAC;
1428 				*(msg+1) = DM;
1429 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1430 					perror("abort");
1431 				fprintf(cout,"ABOR\r\n");
1432 				(void) fflush(cout);
1433 				FD_ZERO(&mask);
1434 				FD_SET(fileno(cin), &mask);
1435 				if ((nfnd = empty(&mask,10)) <= 0) {
1436 					if (nfnd < 0) {
1437 						perror("abort");
1438 					}
1439 					if (ptabflg)
1440 						code = -1;
1441 					lostpeer();
1442 				}
1443 				(void) getreply(0);
1444 				(void) getreply(0);
1445 			}
1446 			pswitch(1);
1447 			if (ptabflg)
1448 				code = -1;
1449 			(void) signal(SIGINT, oldintr);
1450 			return;
1451 		}
1452 	}
1453 	if (cpend) {
1454 		char msg[2];
1455 
1456 		fprintf(cout,"%c%c",IAC,IP);
1457 		(void) fflush(cout);
1458 		*msg = IAC;
1459 		*(msg+1) = DM;
1460 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1461 			perror("abort");
1462 		fprintf(cout,"ABOR\r\n");
1463 		(void) fflush(cout);
1464 		FD_ZERO(&mask);
1465 		FD_SET(fileno(cin), &mask);
1466 		if ((nfnd = empty(&mask,10)) <= 0) {
1467 			if (nfnd < 0) {
1468 				perror("abort");
1469 			}
1470 			if (ptabflg)
1471 				code = -1;
1472 			lostpeer();
1473 		}
1474 		(void) getreply(0);
1475 		(void) getreply(0);
1476 	}
1477 	pswitch(!proxy);
1478 	if (cpend) {
1479 		FD_ZERO(&mask);
1480 		FD_SET(fileno(cin), &mask);
1481 		if ((nfnd = empty(&mask,10)) <= 0) {
1482 			if (nfnd < 0) {
1483 				perror("abort");
1484 			}
1485 			if (ptabflg)
1486 				code = -1;
1487 			lostpeer();
1488 		}
1489 		(void) getreply(0);
1490 		(void) getreply(0);
1491 	}
1492 	if (proxy)
1493 		pswitch(0);
1494 	switch (oldtype) {
1495 		case 0:
1496 			break;
1497 		case TYPE_A:
1498 			setascii();
1499 			break;
1500 		case TYPE_I:
1501 			setbinary();
1502 			break;
1503 		case TYPE_E:
1504 			setebcdic();
1505 			break;
1506 		case TYPE_L:
1507 			settenex();
1508 			break;
1509 	}
1510 	pswitch(1);
1511 	if (ptabflg)
1512 		code = -1;
1513 	(void) signal(SIGINT, oldintr);
1514 }
1515 
1516 reset()
1517 {
1518 	struct fd_set mask;
1519 	int nfnd = 1;
1520 
1521 	FD_ZERO(&mask);
1522 	while (nfnd > 0) {
1523 		FD_SET(fileno(cin), &mask);
1524 		if ((nfnd = empty(&mask,0)) < 0) {
1525 			perror("reset");
1526 			code = -1;
1527 			lostpeer();
1528 		}
1529 		else if (nfnd) {
1530 			(void) getreply(0);
1531 		}
1532 	}
1533 }
1534 
1535 char *
1536 gunique(local)
1537 	char *local;
1538 {
1539 	static char new[MAXPATHLEN];
1540 	char *cp = rindex(local, '/');
1541 	int d, count=0;
1542 	char ext = '1';
1543 
1544 	if (cp)
1545 		*cp = '\0';
1546 	d = access(cp ? local : ".", 2);
1547 	if (cp)
1548 		*cp = '/';
1549 	if (d < 0) {
1550 		perror(local);
1551 		return((char *) 0);
1552 	}
1553 	(void) strcpy(new, local);
1554 	cp = new + strlen(new);
1555 	*cp++ = '.';
1556 	while (!d) {
1557 		if (++count == 100) {
1558 			printf("runique: can't find unique file name.\n");
1559 			return((char *) 0);
1560 		}
1561 		*cp++ = ext;
1562 		*cp = '\0';
1563 		if (ext == '9')
1564 			ext = '0';
1565 		else
1566 			ext++;
1567 		if ((d = access(new, 0)) < 0)
1568 			break;
1569 		if (ext != '0')
1570 			cp--;
1571 		else if (*(cp - 2) == '.')
1572 			*(cp - 1) = '1';
1573 		else {
1574 			*(cp - 2) = *(cp - 2) + 1;
1575 			cp--;
1576 		}
1577 	}
1578 	return(new);
1579 }
1580