diff options
Diffstat (limited to 'Src/Modules')
-rw-r--r-- | Src/Modules/.distfiles | 1 | ||||
-rw-r--r-- | Src/Modules/example.mdd | 3 | ||||
-rw-r--r-- | Src/Modules/files.c | 6 | ||||
-rw-r--r-- | Src/Modules/stat.c | 11 | ||||
-rw-r--r-- | Src/Modules/zftp.c | 142 |
5 files changed, 138 insertions, 25 deletions
diff --git a/Src/Modules/.distfiles b/Src/Modules/.distfiles index 4c98f97ea..23c7eae3f 100644 --- a/Src/Modules/.distfiles +++ b/Src/Modules/.distfiles @@ -5,4 +5,5 @@ DISTFILES_SRC=' example.mdd example.c files.mdd files.c stat.mdd stat.c + zftp.mdd zftp.c ' diff --git a/Src/Modules/example.mdd b/Src/Modules/example.mdd index 89f12097c..f2cd50693 100644 --- a/Src/Modules/example.mdd +++ b/Src/Modules/example.mdd @@ -1,3 +1,6 @@ autobins="example" +autoinfixconds="ex" +autoprefixconds="len" + objects="example.o" diff --git a/Src/Modules/files.c b/Src/Modules/files.c index f52c54338..c1948e1fd 100644 --- a/Src/Modules/files.c +++ b/Src/Modules/files.c @@ -195,18 +195,18 @@ bin_ln(char *nam, char **args, char *ops, int func) if(func == BIN_MV) { - move = rename; + move = (MoveFunc) rename; flags = ops['f'] ? 0 : MV_ASKNW; flags |= MV_ATOMIC; } else { flags = ops['f'] ? MV_FORCE : 0; #ifdef HAVE_LSTAT if(ops['s']) - move = symlink; + move = (MoveFunc) symlink; else #endif { - move = link; + move = (MoveFunc) link; if(!ops['d']) flags |= MV_NODIRS; } diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c index 5c56be5c6..6f80e2a96 100644 --- a/Src/Modules/stat.c +++ b/Src/Modules/stat.c @@ -346,7 +346,7 @@ bin_stat(char *name, char **args, char *ops, int func) } else { for (; *arg; arg++) { if (strchr("glLnNrstT", *arg)) - ops[*arg] = 1; + ops[STOUC(*arg)] = 1; else if (*arg == 'A') { if (arg[1]) { arrnam = arg+1; @@ -505,7 +505,7 @@ bin_stat(char *name, char **args, char *ops, int func) continue; } - if (flags & STF_FILE) + if (flags & STF_FILE) { if (arrnam) *arrptr++ = ztrdup(*args); else if (hashnam) { @@ -513,6 +513,7 @@ bin_stat(char *name, char **args, char *ops, int func) *hashptr++ = ztrdup(*args); } else printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n"); + } if (iwhich > -1) { statprint(&statbuf, outbuf, *args, iwhich, flags); if (arrnam) @@ -544,7 +545,7 @@ bin_stat(char *name, char **args, char *ops, int func) putchar('\n'); } - if (arrnam) + if (arrnam) { if (ret) freearray(array); else { @@ -552,8 +553,9 @@ bin_stat(char *name, char **args, char *ops, int func) if (errflag) return 1; } + } - if (hashnam) + if (hashnam) { if (ret) freearray(hash); else { @@ -561,6 +563,7 @@ bin_stat(char *name, char **args, char *ops, int func) if (errflag) return 1; } + } return ret; } diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 4bcd80c7f..d71fa642f 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -62,9 +62,19 @@ /* it's a TELNET based protocol, but don't think I like doing this */ #include <arpa/telnet.h> +/* + * We use poll() in preference to select because some subset of manuals says + * that's the thing to do, plus it's a bit less fiddly. I don't actually + * have access to a system with poll but not select, however, though + * both bits of the code have been tested on a machine with both. + */ +#ifdef HAVE_POLL_H +# include <poll.h> +#endif + /* pinch the definition from <netinet/in.h> for deficient headers */ #ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff +# define INADDR_NONE 0xffffffff #endif /* @@ -124,7 +134,8 @@ enum { ZFTP_HERE = 0x0100, /* here rather than over there */ ZFTP_CDUP = 0x0200, /* CDUP rather than CWD */ ZFTP_REST = 0x0400, /* restart: set point in remote file */ - ZFTP_RECV = 0x0800 /* receive rather than send */ + ZFTP_RECV = 0x0800, /* receive rather than send */ + ZFTP_TEST = 0x1000 /* test command, don't test */ }; typedef struct zftpcmd *Zftpcmd; @@ -134,6 +145,7 @@ static struct zftpcmd zftpcmdtab[] = { { "params", zftp_params, 0, 4, 0 }, { "login", zftp_login, 0, 3, ZFTP_CONN }, { "user", zftp_login, 0, 3, ZFTP_CONN }, + { "test", zftp_test, 0, 0, ZFTP_TEST }, { "cd", zftp_cd, 1, 1, ZFTP_CONN|ZFTP_LOGI }, { "cdup", zftp_cd, 0, 0, ZFTP_CONN|ZFTP_LOGI|ZFTP_CDUP }, { "dir", zftp_dir, 0, -1, ZFTP_CONN|ZFTP_LOGI }, @@ -674,8 +686,8 @@ zfgetmsg() zfgetline(line, 256, tmout); ptr = line; - if (zfdrrrring || !isdigit((int)*ptr) || !isdigit((int)ptr[1]) || - !isdigit((int)ptr[2])) { + if (zfdrrrring || !isdigit(STOUC(*ptr)) || !isdigit(STOUC(ptr[1])) || + !isdigit(STOUC(ptr[2]))) { /* timeout, or not talking FTP. not really interested. */ zcfinish = 2; if (!zfclosing) @@ -820,7 +832,7 @@ zfopendata(char *name) zwarnnam(name, "Must set preference S or P to transfer data", NULL, 0); return 1; } - zdfd = zfmovefd(socket(AF_INET, SOCK_STREAM, 0)); + zdfd = socket(AF_INET, SOCK_STREAM, 0); if (zdfd < 0) { zwarnnam(name, "can't get data socket: %e", NULL, errno); return 1; @@ -851,7 +863,7 @@ zfopendata(char *name) * lastmsg already has the reply code expunged. */ for (ptr = lastmsg; *ptr; ptr++) - if (isdigit(*ptr)) + if (isdigit(STOUC(*ptr))) break; if (sscanf(ptr, "%d,%d,%d,%d,%d,%d", nums, nums+1, nums+2, nums+3, nums+4, nums+5) != 6) { @@ -986,11 +998,11 @@ zfgetdata(char *name, char *rest, char *cmd, int getsize) char *ptr = strstr(lastmsg, "bytes"); zfstatus |= ZFST_NOSZ|ZFST_TRSZ; if (ptr) { - while (ptr > lastmsg && !isdigit(*ptr)) + while (ptr > lastmsg && !isdigit(STOUC(*ptr))) ptr--; - while (ptr > lastmsg && isdigit(ptr[-1])) + while (ptr > lastmsg && isdigit(STOUC(ptr[-1]))) ptr--; - if (isdigit(*ptr)) { + if (isdigit(STOUC(*ptr))) { zfstatus &= ~ZFST_NOSZ; if (getsize) { long sz = zstrtol(ptr, NULL, 10); @@ -1017,6 +1029,13 @@ zfgetdata(char *name, char *rest, char *cmd, int getsize) return 1; } zdfd = newfd; /* this is now the actual data fd */ + } else { + /* + * We avoided dup'ing zdfd up to this point, to try to keep + * things simple, so we now need to move it out of the way + * of the user-visible fd's. + */ + zdfd = zfmovefd(zdfd); } @@ -1659,7 +1678,7 @@ zftp_open(char *name, char **args, int flags) } zsock.sin_port = zservp->s_port; - zcfd = zfmovefd(socket(zsock.sin_family, SOCK_STREAM, 0)); + zcfd = socket(zsock.sin_family, SOCK_STREAM, 0); if (zcfd < 0) { zwarnnam(name, "socket failed: %e", NULL, errno); zfunsetparam("ZFTP_HOST"); @@ -1667,12 +1686,6 @@ zftp_open(char *name, char **args, int flags) return 1; } -#if defined(F_SETFD) && defined(FD_CLOEXEC) - /* If the shell execs a program, we don't want this fd left open. */ - len = FD_CLOEXEC; - fcntl(zcfd, F_SETFD, &len); -#endif - /* * now connect the socket. manual pages all say things like `this is all * explained oh-so-wonderfully in some other manual page'. not. @@ -1708,6 +1721,19 @@ zftp_open(char *name, char **args, int flags) /* now we can talk to the control connection */ zcfinish = 0; + + /* + * Move the fd out of the user-visible range. We need to do + * this after the connect() on some systems. + */ + zcfd = zfmovefd(zcfd); + +#if defined(F_SETFD) && defined(FD_CLOEXEC) + /* If the shell execs a program, we don't want this fd left open. */ + len = FD_CLOEXEC; + fcntl(zcfd, F_SETFD, &len); +#endif + len = sizeof(zsock); if (getsockname(zcfd, (struct sockaddr *)&zsock, &len) < 0) { zwarnnam(name, "getsockname failed: %e", NULL, errno); @@ -2022,6 +2048,69 @@ zftp_login(char *name, char **args, int flags) return zfgetcwd(); } +/* + * See if the server wants to tell us something. On a timeout, we usually + * have a `421 Timeout' or something such waiting for us, so we read + * it here. As well as being called explicitly by the user + * (precmd is a very good place for this, it's cheap since it has + * no network overhead), we call it in the bin_zftp front end if we + * have a connection and weren't going to call it anyway. + * + * Poll-free and select-free systems are few and far between these days, + * but I'm willing to consider suggestions. + */ + +/**/ +static int +zftp_test(char *name, char **args, int flags) +{ +#if defined(HAVE_POLL) || defined(HAVE_SELECT) + int ret; +# ifdef HAVE_POLL + struct pollfd pfd; +# else + fd_set f; + struct timeval tv; +# endif /* HAVE_POLL */ + + if (zcfd == -1) + return 1; + +# ifdef HAVE_POLL +# ifndef POLLIN + /* safety first, though I think POLLIN is more common */ +# define POLLIN POLLNORM +# endif /* HAVE_POLL */ + pfd.fd = zcfd; + pfd.events = POLLIN; + if ((ret = poll(&pfd, 1, 0)) < 0 && errno != EINTR && errno != EAGAIN) + zfclose(); + else if (ret > 0 && pfd.revents) { + /* handles 421 (maybe a bit noisily?) */ + zfgetmsg(); + } +# else + FD_ZERO(&f); + FD_SET(zcfd, &f); + tv.tv_sec = 0; + tv.tv_usec = 0; + if ((ret = select(zcfd +1, (SELECT_ARG_2_T) &f, NULL, NULL, &tv)) < 0 + && errno != EINTR) + zfclose(); + else if (ret > 0) { + /* handles 421 */ + zfgetmsg(); + } +# endif /* HAVE_POLL */ + /* if we now have zcfd == -1, then we've just been dumped out. */ + return (zcfd == -1) ? 2 : 0; +#else + zfwarnnam(name, "not supported on this system.", NULL, 0); + return 3; +#endif /* defined(HAVE_POLL) || defined(HAVE_SELECT) */ +} + + /* do ls or dir on the remote directory */ /**/ @@ -2476,7 +2565,7 @@ bin_zftp(char *name, char **args, char *ops, int func) char fullname[11] = "zftp "; char *cnam = *args++, *prefs, *ptr; Zftpcmd zptr; - int n, ret; + int n, ret = 0; for (zptr = zftpcmdtab; zptr->nam; zptr++) if (!strcmp(zptr->nam, cnam)) @@ -2521,8 +2610,25 @@ bin_zftp(char *name, char **args, char *ops, int func) "B" : "S"), ZFPM_READONLY); } } +#if defined(HAVE_SELECT) || defined (HAVE_POLL) + if (zcfd != -1 && !(zptr->flags & ZFTP_TEST)) { + /* + * Test the connection for a bad fd or incoming message, but + * only if the connection was last heard of open, and + * if we are not about to call the test command anyway. + * Not worth it unless we have select() or poll(). + */ + ret = zftp_test("zftp test", NULL, 0); + } +#endif if ((zptr->flags & ZFTP_CONN) && zcfd == -1) { - zwarnnam(fullname, "not connected.", NULL, 0); + if (ret != 2) { + /* + * with ret == 2, we just got dumped out in the test, + * so enough messages already. + */ + zwarnnam(fullname, "not connected.", NULL, 0); + } return 1; } |