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