This is a discussion on Re: tftp diff within the lucky.openbsd.tech forums, part of the OpenBSD category; --> After reading your explanation I agree with you. Attached the reworked diff which kills also the last setjmp() and ...
| |||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| After reading your explanation I agree with you. Attached the reworked diff which kills also the last setjmp() and handles ctrl-c by catching it with a poll() loop wrapped in front of the fgets() call. Tested it and works OK for me. On Thu, Apr 27, 2006 at 12:25:08PM -0600, Theo de Raadt wrote: > > The setjmp(3) in main.c which is used when ctrl-c is catched (SIGINT) > > is kept which is legitim IMO for that use and done this way by a lot > > of command line programs (ftp, ed, restore etc.) to return to the > > command prompt no matter which routine was active (e.g. blocking > > fgets(3)). > > Well, just because lots of programs use that method does not make it > legitimate, because in the end I must say this: IT IS STILL NOT SAFE. > > Think about it. > > When that ^C comes in, is it not possible that our code is currently running > inside malloc()? Just picking an example here, but what about stdio? Or > who knows what else? > > So then the signal comes in, and we longjmp back into main, and now what? > > Now your malloc heap is unsafe. Or stdio is in an inconsistant state. > Or who knows what else. > > And now the code WILL crash later on. And there is no solution to > this besides adding signal blocking stubs all through the code, for > everytime you wish to do something which might conceiveably not be > re-entrant. > > So while it might be what a lot of programs do, my point is that it > is 100% unsafe -- in all cases -- to ever use setjmp. Well, I have > actually used it safely in one program before, but the costs are very > high because you really must do signal blocks around just about any > sequence of code which calls a function which is NOT LISTED in signal.h > > This is what I call a reverse signal race. -- Marcus Glocker, marcus@nazgul.ch, http://www.nazgul.ch ----------------- diff -urN -x CVS src/usr.bin/tftp.orig/main.c src/usr.bin/tftp/main.c --- src/usr.bin/tftp.orig/main.c Wed Apr 26 12:36:12 2006 +++ src/usr.bin/tftp/main.c Fri Apr 28 20:17:26 2006 @@ -48,34 +48,35 @@ /* * TFTP User Program -- Command Interface. */ + #include <sys/param.h> #include <sys/socket.h> #include <sys/file.h> #include <netinet/in.h> - #include <arpa/inet.h> #include <ctype.h> #include <errno.h> #include <netdb.h> -#include <setjmp.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <err.h> +#include <poll.h> #include "extern.h" #define TIMEOUT 5 /* secs between rexmt's */ #define LBUFLEN 200 /* size of input buffer */ #define MAXARGV 20 +#define HELPINDENT (sizeof("connect")) struct sockaddr_in peeraddr; int f; -short port; +short port; int trace; int verbose; int connected; @@ -84,10 +85,15 @@ int margc; char *margv[MAXARGV+1]; char *prompt = "tftp"; -jmp_buf toplevel; void intr(int); struct servent *sp; +int rexmtval = TIMEOUT; +int maxtimeout = 5 * TIMEOUT; +char hostname[MAXHOSTNAMELEN]; +FILE *file = NULL; +volatile sig_atomic_t intrflag = 0; + void get(int, char **); void help(int, char **); void modecmd(int, char **); @@ -101,6 +107,7 @@ void settrace(int, char **); void setverbose(int, char **); void status(int, char **); +int readcmd(char *, int, FILE *); static __dead void command(void); @@ -109,8 +116,6 @@ static void putusage(char *); static void settftpmode(char *); -#define HELPINDENT (sizeof("connect")) - struct cmd { char *name; char *help; @@ -128,8 +133,8 @@ char sthelp[] = "show current status"; char xhelp[] = "set per-packet retransmission timeout"; char ihelp[] = "set total retransmission timeout"; -char ashelp[] = "set mode to netascii"; -char bnhelp[] = "set mode to octet"; +char ashelp[] = "set mode to netascii"; +char bnhelp[] = "set mode to octet"; struct cmd cmdtab[] = { { "connect", chelp, setpeer }, @@ -144,10 +149,24 @@ { "ascii", ashelp, setascii }, { "rexmt", xhelp, setrexmt }, { "timeout", ihelp, settimeout }, + { "help", hhelp, help }, { "?", hhelp, help }, { NULL, NULL, NULL } }; +struct modes { + char *m_name; + char *m_mode; +} modes[] = { + { "ascii", "netascii" }, + { "netascii", "netascii" }, + { "binary", "octet" }, + { "image", "octet" }, + { "octet", "octet" }, +/* { "mail", "mail" }, */ + { NULL, NULL } +}; + struct cmd *getcmd(char *); char *tail(char *); @@ -156,31 +175,34 @@ { struct sockaddr_in s_in; + /* socket, bind */ sp = getservbyname("tftp", "udp"); if (sp == 0) errx(1, "udp/tftp: unknown service"); f = socket(AF_INET, SOCK_DGRAM, 0); if (f < 0) err(3, "socket"); - bzero((char *)&s_in, sizeof (s_in)); + bzero((char *)&s_in, sizeof(s_in)); s_in.sin_family = AF_INET; - if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) + if (bind(f, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) err(1, "bind"); - strlcpy(mode, "netascii", sizeof mode); - signal(SIGINT, intr); - if (argc > 1) { - if (setjmp(toplevel) != 0) - exit(0); + + /* set default transfer mode */ + strlcpy(mode, "netascii", sizeof(mode)); + + /* set peer if given */ + if (argc > 1) setpeer(argc, argv); - } - if (setjmp(toplevel) != 0) - (void)putchar('\n'); + + /* catch SIGINT */ + signal(SIGINT, intr); + + /* command prompt */ command(); + return (0); } -char hostname[MAXHOSTNAMELEN]; - void setpeer(int argc, char *argv[]) { @@ -189,7 +211,7 @@ if (argc < 2) { strlcpy(line, "Connect ", sizeof line); printf("(to) "); - fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); + readcmd(&line[strlen(line)], LBUFLEN-strlen(line), stdin); if (makeargv()) return; argc = margc; @@ -227,19 +249,6 @@ connected = 1; } -struct modes { - char *m_name; - char *m_mode; -} modes[] = { - { "ascii", "netascii" }, - { "netascii", "netascii" }, - { "binary", "octet" }, - { "image", "octet" }, - { "octet", "octet" }, -/* { "mail", "mail" }, */ - { NULL, NULL } -}; - void modecmd(int argc, char *argv[]) { @@ -276,14 +285,12 @@ void setbinary(int argc, char *argv[]) { - settftpmode("octet"); } void setascii(int argc, char *argv[]) { - settftpmode("netascii"); } @@ -295,7 +302,6 @@ printf("mode set to %s\n", mode); } - /* * Send file(s). */ @@ -309,7 +315,7 @@ if (argc < 2) { strlcpy(line, "send ", sizeof line); printf("(file) "); - fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); + readcmd(&line[strlen(line)], LBUFLEN - strlen(line), stdin); if (makeargv()) return; argc = margc; @@ -362,8 +368,10 @@ return; } - /* this assumes the target is a directory */ - /* on a remote unix system. hmmmm. */ + /* + * this assumes the target is a directory on + * on a remote unix system. hmmmm. + */ for (n = 1; n < argc - 1; n++) { if (asprintf(&cp, "%s/%s", targ, tail(argv[n])) == -1) err(1, "asprintf"); @@ -386,7 +394,8 @@ putusage(char *s) { printf("usage: %s file [[host:]remotename]\n", s); - printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s); + printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", + s); } /* @@ -403,7 +412,7 @@ if (argc < 2) { strlcpy(line, "get ", sizeof line); printf("(files) "); - fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); + readcmd(&line[strlen(line)], LBUFLEN-strlen(line), stdin); if (makeargv()) return; argc = margc; @@ -474,8 +483,6 @@ printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s); } -int rexmtval = TIMEOUT; - void setrexmt(int argc, char *argv[]) { @@ -484,7 +491,7 @@ if (argc < 2) { strlcpy(line, "Rexmt-timeout ", sizeof line); printf("(value) "); - fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); + readcmd(&line[strlen(line)], LBUFLEN-strlen(line), stdin); if (makeargv()) return; argc = margc; @@ -501,8 +508,6 @@ rexmtval = t; } -int maxtimeout = 5 * TIMEOUT; - void settimeout(int argc, char *argv[]) { @@ -511,7 +516,7 @@ if (argc < 2) { strlcpy(line, "Maximum-timeout ", sizeof line); printf("(value) "); - fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin); + readcmd(&line[strlen(line)], LBUFLEN-strlen(line), stdin); if (makeargv()) return; argc = margc; @@ -544,10 +549,7 @@ void intr(int signo) { - - signal(SIGALRM, SIG_IGN); - alarm(0); - longjmp(toplevel, -1); + intrflag = 1; } char * @@ -576,13 +578,8 @@ for (; printf("%s> ", prompt); - if (fgets(line, LBUFLEN, stdin) == 0) { - if (feof(stdin)) { - exit(0); - } else { - continue; - } - } + if (readcmd(line, LBUFLEN, stdin) < 1) + continue; if ((line[0] == 0) || (line[0] == '\n')) continue; if (makeargv()) @@ -612,6 +609,7 @@ longest = 0; nmatches = 0; found = 0; + intrflag = 0; for (c = cmdtab; (p = c->name) != NULL; c++) { for (q = name; *q == *p++; q++) if (*q == 0) /* exact match? */ @@ -666,7 +664,6 @@ void quit(int argc, char *argv[]) { - exit(0); } @@ -709,4 +706,34 @@ { verbose = !verbose; printf("Verbose mode %s.\n", verbose ? "on" : "off"); +} + +int +readcmd(char *input, int len, FILE *stream) +{ + int nfds; + struct pollfd pfd[1]; + + fflush(stdout); + + pfd[0].fd = 0; + pfd[0].events = POLLIN; + nfds = poll(pfd, 1, -1); + if (nfds == -1) { + if (intrflag) { + intrflag = 0; + putchar('\n'); + return (0); + } + exit(1); + } + + if (fgets(input, len, stream) == NULL) { + if (feof(stdin)) + exit(0); + else + return (-1); + } + + return (1); } diff -urN -x CVS src/usr.bin/tftp.orig/tftp.c src/usr.bin/tftp/tftp.c --- src/usr.bin/tftp.orig/tftp.c Tue Apr 25 22:08:37 2006 +++ src/usr.bin/tftp/tftp.c Fri Apr 28 20:17:46 2006 @@ -42,16 +42,16 @@ /* * TFTP User Program -- Protocol Machines */ + #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> - #include <arpa/tftp.h> #include <errno.h> -#include <setjmp.h> +#include <poll.h> #include <signal.h> #include <stdio.h> #include <stddef.h> @@ -62,40 +62,57 @@ #include "extern.h" #include "tftpsubs.h" +#define PKTSIZE SEGSIZE + 4 -extern struct sockaddr_in peeraddr; /* filled in by main */ -extern int f; /* the opened socket */ -extern int trace; -extern int verbose; -extern int rexmtval; -extern int maxtimeout; +extern struct sockaddr_in peeraddr; /* filled in by main */ +extern int f; /* the opened socket */ +extern int trace; +extern int verbose; +extern int rexmtval; +extern int maxtimeout; +extern FILE *file; +extern volatile sig_atomic_t intrflag; -#define PKTSIZE SEGSIZE+4 -char ackbuf[PKTSIZE]; -int timeout; -jmp_buf toplevel; -jmp_buf timeoutbuf; +char ackbuf[PKTSIZE]; -static void nak(int); -static int makerequest(int, const char *, struct tftphdr *, const char *); -static void printstats(const char *, unsigned long); -static void startclock(void); -static void stopclock(void); -static void timer(int); -static void tpacket(const char *, struct tftphdr *, int); +struct timeval tstart; +struct timeval tstop; +struct errmsg { + int e_code; + char *e_msg; +} errmsgs[] = { + { EUNDEF, "Undefined error code" }, + { ENOTFOUND, "File not found" }, + { EACCESS, "Access violation" }, + { ENOSPACE, "Disk full or allocation exceeded" }, + { EBADOP, "Illegal TFTP operation" }, + { EBADID, "Unknown transfer ID" }, + { EEXISTS, "File already exists" }, + { ENOUSER, "No such user" }, + { -1, NULL } +}; + +static int makerequest(int, const char *, struct tftphdr *, const char *); +static void nak(int); +static void tpacket(const char *, struct tftphdr *, int); +static void startclock(void); +static void stopclock(void); +static void printstats(const char *, unsigned long); +static void printtimeout(void); + /* * Send the requested file. */ void sendfile(int fd, char *name, char *mode) { - struct tftphdr *dp, *ap; /* data and ack packets */ - volatile int block, size, convert; - volatile unsigned long amount; + struct tftphdr *dp, *ap; /* data and ack packets */ struct sockaddr_in from; - int n, fromlen; - FILE *file; + struct pollfd pfd[1]; + unsigned long amount; + int convert; /* true if converting crlf -> lf */ + int n, nfds, error, fromlen, timeouts, block, size; startclock(); /* start stat's clock */ dp = r_init(); /* reset fillbuf/read-ahead code */ @@ -105,12 +122,11 @@ block = 0; amount = 0; - signal(SIGALRM, timer); do { - if (block == 0) + /* read data from file */ + if (!block) size = makerequest(WRQ, name, dp, mode) - 4; else { - /* size = read(fd, dp->th_data, SEGSIZE); */ size = readit(file, &dp, convert); if (size < 0) { nak(errno + 100); @@ -119,66 +135,93 @@ dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); } - timeout = 0; - (void) setjmp(timeoutbuf); -send_data: - if (trace) - tpacket("sent", dp, size + 4); - n = sendto(f, dp, size + 4, 0, - (struct sockaddr *)&peeraddr, sizeof(peeraddr)); - if (n != size + 4) { - warn("sendto"); - goto abort; - } - read_ahead(file, convert); - for ( ; ; ) { - alarm(rexmtval); - do { - fromlen = sizeof(from); - n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, - (struct sockaddr *)&from, &fromlen); - } while (n <= 0); - alarm(0); - if (n < 0) { + + /* send data to server and wait for server ACK */ + for (timeouts = 0, error = 0; !intrflag + if (timeouts == maxtimeout) { + printtimeout(); + goto abort; + } + + if (!error) { + if (trace) + tpacket("sent", dp, size + 4); + if (sendto(f, dp, size + 4, 0, + (struct sockaddr *)&peeraddr, + sizeof(peeraddr)) != size + 4) { + warn("sendto"); + goto abort; + } + read_ahead(file, convert); + } + error = 0; + + pfd[0].fd = f; + pfd[0].events = POLLIN; + nfds = poll(pfd, 1, rexmtval * 1000); + if (nfds == 0) { + timeouts++; + continue; + } + if (nfds == -1) { + error = 1; + if (errno == EINTR) + continue; + warn("poll"); + goto abort; + } + fromlen = sizeof(from); + n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, + (struct sockaddr *)&from, &fromlen); + if (n == 0) { warn("recvfrom"); goto abort; } + if (n == -1) { + error = 1; + if (errno == EINTR) + continue; + warn("recvfrom"); + goto abort; + } peeraddr.sin_port = from.sin_port; /* added */ if (trace) tpacket("received", ap, n); - /* should verify packet came from server */ ap->th_opcode = ntohs(ap->th_opcode); ap->th_block = ntohs(ap->th_block); + if (ap->th_opcode == ERROR) { - printf("Error code %d: %s\n", ap->th_code, - ap->th_msg); + printf("Error code %d: %s\n", + ap->th_code, ap->th_msg); goto abort; } if (ap->th_opcode == ACK) { int j; - - if (ap->th_block == block) { + if (ap->th_block == block) break; - } - /* On an error, try to synchronize - * both sides. - */ + /* re-synchronize with other side */ j = synchnet(f); if (j && trace) printf("discarded %d packets\n", j); - if (ap->th_block == (block-1)) - goto send_data; + if (ap->th_block == (block - 1)) + continue; } + error = 1; /* received packet does not match */ } + if (block > 0) amount += size; block++; - } while (size == SEGSIZE || block == 1); + } while ((size == SEGSIZE || block == 1) && !intrflag); + abort: fclose(file); stopclock(); - if (amount > 0) + if (amount > 0) { + if (intrflag) + putchar('\n'); printstats("Sent", amount); + } } /* @@ -187,25 +230,25 @@ void recvfile(int fd, char *name, char *mode) { - struct tftphdr *dp, *ap; - volatile int block, size, firsttrip; - volatile unsigned long amount; + struct tftphdr *dp, *ap; /* data and ack packets */ struct sockaddr_in from; - int n, fromlen; - FILE *file; - volatile int convert; /* true if converting crlf -> lf */ + struct pollfd pfd[1]; + unsigned long amount; + int convert; /* true if converting crlf -> lf */ + int n, nfds, error, fromlen, timeouts, block, size, firsttrip; - startclock(); - dp = w_init(); + startclock(); /* start stat's clock */ + dp = w_init(); /* reset fillbuf/read-ahead code */ ap = (struct tftphdr *)ackbuf; file = fdopen(fd, "w"); convert = !strcmp(mode, "netascii"); + n = 0; block = 1; - firsttrip = 1; amount = 0; + firsttrip = 1; - signal(SIGALRM, timer); do { + /* create new ACK packet */ if (firsttrip) { size = makerequest(RRQ, name, ap, mode); firsttrip = 0; @@ -215,75 +258,104 @@ size = 4; block++; } - timeout = 0; - (void) setjmp(timeoutbuf); -send_ack: - if (trace) - tpacket("sent", ap, size); - if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr, - sizeof(peeraddr)) != size) { - alarm(0); - warn("sendto"); - goto abort; - } - write_behind(file, convert); - for ( ; ; ) { - alarm(rexmtval); - do { - fromlen = sizeof(from); - n = recvfrom(f, dp, PKTSIZE, 0, - (struct sockaddr *)&from, &fromlen); - } while (n <= 0); - alarm(0); - if (n < 0) { + + /* send ACK to server and wait for server data */ + for (timeouts = 0, error = 0; !intrflag + if (timeouts == maxtimeout) { + printtimeout(); + goto abort; + } + + if (!error) { + if (trace) + tpacket("sent", ap, size); + if (sendto(f, ackbuf, size, 0, + (struct sockaddr *)&peeraddr, + sizeof(peeraddr)) != size) { + warn("sendto"); + goto abort; + } + write_behind(file, convert); + } + error = 0; + + pfd[0].fd = f; + pfd[0].events = POLLIN; + nfds = poll(pfd, 1, rexmtval * 1000); + if (nfds == 0) { + timeouts++; + continue; + } + if (nfds == -1) { + error = 1; + if (errno == EINTR) + continue; + warn("poll"); + goto abort; + } + fromlen = sizeof(from); + n = recvfrom(f, dp, PKTSIZE, 0, + (struct sockaddr *)&from, &fromlen); + if (n == 0) { warn("recvfrom"); goto abort; } + if (n == -1) { + error = 1; + if (errno == EINTR) + continue; + warn("recvfrom"); + goto abort; + } peeraddr.sin_port = from.sin_port; /* added */ if (trace) tpacket("received", dp, n); - /* should verify client address */ dp->th_opcode = ntohs(dp->th_opcode); dp->th_block = ntohs(dp->th_block); + if (dp->th_opcode == ERROR) { - printf("Error code %d: %s\n", dp->th_code, - dp->th_msg); + printf("Error code %d: %s\n", + dp->th_code, dp->th_msg); goto abort; } if (dp->th_opcode == DATA) { int j; - - if (dp->th_block == block) { - break; /* have next packet */ - } - /* On an error, try to synchronize - * both sides. - */ + if (dp->th_block == block) + break; + /* re-synchronize with other side */ j = synchnet(f); if (j && trace) printf("discarded %d packets\n", j); - if (dp->th_block == (block-1)) - goto send_ack; /* resend ack */ + if (dp->th_block == (block - 1)) + continue; } + error = 1; /* received packet does not match */ } - /* size = write(fd, dp->th_data, n - 4); */ + + /* write data to file */ size = writeit(file, &dp, n - 4, convert); if (size < 0) { nak(errno + 100); break; } amount += size; - } while (size == SEGSIZE); -abort: /* ok to ack, since user */ - ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ + } while (size == SEGSIZE && !intrflag); + +abort: + /* ok to ack, since user has seen err msg */ + ap->th_opcode = htons((u_short)ACK); ap->th_block = htons((u_short)block); (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr, sizeof(peeraddr)); - write_behind(file, convert); /* flush last buffer */ + write_behind(file, convert); /* flush last buffer */ + fclose(file); stopclock(); - if (amount > 0) + if (amount > 0) { + if (intrflag) + putchar('\n'); printstats("Received", amount); + } } static int @@ -303,21 +375,6 @@ return (cp + len - (char *)tp); } -struct errmsg { - int e_code; - char *e_msg; -} errmsgs[] = { - { EUNDEF, "Undefined error code" }, - { ENOTFOUND, "File not found" }, - { EACCESS, "Access violation" }, - { ENOSPACE, "Disk full or allocation exceeded" }, - { EBADOP, "Illegal TFTP operation" }, - { EBADID, "Unknown transfer ID" }, - { EEXISTS, "File already exists" }, - { ENOUSER, "No such user" }, - { -1, NULL } -}; - /* * Send a nak packet (error message). * Error code passed in is one of the @@ -355,7 +412,7 @@ tpacket(const char *s, struct tftphdr *tp, int n) { static char *opcodes[] = - { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; + { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; char *cp, *file; u_short op = ntohs(tp->th_opcode); @@ -363,8 +420,8 @@ printf("%s opcode=%x ", s, op); else printf("%s %s ", s, opcodes[op]); - switch (op) { + switch (op) { case RRQ: case WRQ: n -= 2; @@ -372,36 +429,28 @@ cp = strchr(cp, '\0'); printf("<file=%s, mode=%s>\n", file, cp + 1); break; - case DATA: printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); break; - case ACK: printf("<block=%d>\n", ntohs(tp->th_block)); break; - case ERROR: printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); break; } } -struct timeval tstart; -struct timeval tstop; - static void startclock(void) { - - (void)gettimeofday(&tstart, NULL); + (void) gettimeofday(&tstart, NULL); } static void stopclock(void) { - - (void)gettimeofday(&tstop, NULL); + (void) gettimeofday(&tstop, NULL); } static void @@ -410,26 +459,17 @@ double delta; /* compute delta in 1/10's second units */ - delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - - ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); - delta = delta/10.; /* back to seconds */ + delta = ((tstop.tv_sec * 10.) + (tstop.tv_usec / 100000)) - + ((tstart.tv_sec * 10.) + (tstart.tv_usec / 100000)); + delta = delta / 10.; /* back to seconds */ printf("%s %lu bytes in %.1f seconds", direction, amount, delta); if (verbose) - printf(" [%.0f bits/sec]", (amount*8.)/delta); + printf(" [%.0f bits/sec]", (amount * 8.) / delta); putchar('\n'); } static void -timer(int sig) +printtimeout(void) { - int save_errno = errno; - - timeout += rexmtval; - if (timeout >= maxtimeout) { - printf("Transfer timed out.\n"); - errno = save_errno; - longjmp(toplevel, -1); - } - errno = save_errno; - longjmp(timeoutbuf, 1); + printf("Transfer timed out.\n"); } |