diff options
author | gavin <gavin@FreeBSD.org> | 2011-06-19 16:54:06 +0000 |
---|---|---|
committer | gavin <gavin@FreeBSD.org> | 2011-06-19 16:54:06 +0000 |
commit | cd23bc1631ac018f140ef5d8cfa8fd8afa0d28e1 (patch) | |
tree | d536f826304d5d1048670212a5e33e4818109b14 /contrib/lukemftp/src/util.c | |
parent | 7e8a9605b1b776a2e6c8f20d00d300a4c160d2fc (diff) | |
download | FreeBSD-src-cd23bc1631ac018f140ef5d8cfa8fd8afa0d28e1.zip FreeBSD-src-cd23bc1631ac018f140ef5d8cfa8fd8afa0d28e1.tar.gz |
Bootstrap lukemftp vendor area
Diffstat (limited to 'contrib/lukemftp/src/util.c')
-rw-r--r-- | contrib/lukemftp/src/util.c | 1400 |
1 files changed, 0 insertions, 1400 deletions
diff --git a/contrib/lukemftp/src/util.c b/contrib/lukemftp/src/util.c deleted file mode 100644 index 6f94bb0..0000000 --- a/contrib/lukemftp/src/util.c +++ /dev/null @@ -1,1400 +0,0 @@ -/* $NetBSD: util.c,v 1.123 2005/05/14 18:56:45 dsl Exp $ */ - -/*- - * Copyright (c) 1997-2005 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Luke Mewburn. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, - * NASA Ames Research Center. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -__RCSID("$NetBSD: util.c,v 1.123 2005/05/14 18:56:45 dsl Exp $"); -#endif /* not lint */ - -/* - * FTP User Program -- Misc support routines - */ -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <arpa/ftp.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <glob.h> -#include <signal.h> -#include <limits.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <termios.h> -#include <time.h> -#include <unistd.h> - -#include "ftp_var.h" - -#define TM_YEAR_BASE 1900 - -/* - * Connect to peer server and auto-login, if possible. - */ -void -setpeer(int argc, char *argv[]) -{ - char *host; - char *port; - - if (argc == 0) - goto usage; - if (connected) { - fprintf(ttyout, "Already connected to %s, use close first.\n", - hostname); - code = -1; - return; - } - if (argc < 2) - (void)another(&argc, &argv, "to"); - if (argc < 2 || argc > 3) { - usage: - fprintf(ttyout, "usage: %s host-name [port]\n", argv[0]); - code = -1; - return; - } - if (gatemode) - port = gateport; - else - port = ftpport; - if (argc > 2) - port = argv[2]; - - if (gatemode) { - if (gateserver == NULL || *gateserver == '\0') - errx(1, "gateserver not defined (shouldn't happen)"); - host = hookup(gateserver, port); - } else - host = hookup(argv[1], port); - - if (host) { - if (gatemode && verbose) { - fprintf(ttyout, - "Connecting via pass-through server %s\n", - gateserver); - } - - connected = 1; - /* - * Set up defaults for FTP. - */ - (void)strlcpy(typename, "ascii", sizeof(typename)); - type = TYPE_A; - curtype = TYPE_A; - (void)strlcpy(formname, "non-print", sizeof(formname)); - form = FORM_N; - (void)strlcpy(modename, "stream", sizeof(modename)); - mode = MODE_S; - (void)strlcpy(structname, "file", sizeof(structname)); - stru = STRU_F; - (void)strlcpy(bytename, "8", sizeof(bytename)); - bytesize = 8; - if (autologin) - (void)ftp_login(argv[1], NULL, NULL); - } -} - -static void -parse_feat(const char *line) -{ - - /* - * work-around broken ProFTPd servers that can't - * even obey RFC 2389. - */ - while (*line && isspace((int)*line)) - line++; - - if (strcasecmp(line, "MDTM") == 0) - features[FEAT_MDTM] = 1; - else if (strncasecmp(line, "MLST", sizeof("MLST") - 1) == 0) { - features[FEAT_MLST] = 1; - } else if (strcasecmp(line, "REST STREAM") == 0) - features[FEAT_REST_STREAM] = 1; - else if (strcasecmp(line, "SIZE") == 0) - features[FEAT_SIZE] = 1; - else if (strcasecmp(line, "TVFS") == 0) - features[FEAT_TVFS] = 1; -} - -/* - * Determine the remote system type (SYST) and features (FEAT). - * Call after a successful login (i.e, connected = -1) - */ -void -getremoteinfo(void) -{ - int overbose, i; - - overbose = verbose; - if (debug == 0) - verbose = -1; - - /* determine remote system type */ - if (command("SYST") == COMPLETE) { - if (overbose) { - char *cp, c; - - c = 0; - cp = strchr(reply_string + 4, ' '); - if (cp == NULL) - cp = strchr(reply_string + 4, '\r'); - if (cp) { - if (cp[-1] == '.') - cp--; - c = *cp; - *cp = '\0'; - } - - fprintf(ttyout, "Remote system type is %s.\n", - reply_string + 4); - if (cp) - *cp = c; - } - if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { - if (proxy) - unix_proxy = 1; - else - unix_server = 1; - /* - * Set type to 0 (not specified by user), - * meaning binary by default, but don't bother - * telling server. We can use binary - * for text files unless changed by the user. - */ - type = 0; - (void)strlcpy(typename, "binary", sizeof(typename)); - if (overbose) - fprintf(ttyout, - "Using %s mode to transfer files.\n", - typename); - } else { - if (proxy) - unix_proxy = 0; - else - unix_server = 0; - if (overbose && - !strncmp(reply_string, "215 TOPS20", 10)) - fputs( -"Remember to set tenex mode when transferring binary files from this machine.\n", - ttyout); - } - } - - /* determine features (if any) */ - for (i = 0; i < FEAT_max; i++) - features[i] = -1; - reply_callback = parse_feat; - if (command("FEAT") == COMPLETE) { - for (i = 0; i < FEAT_max; i++) { - if (features[i] == -1) - features[i] = 0; - } - features[FEAT_FEAT] = 1; - } else - features[FEAT_FEAT] = 0; - if (debug) { -#define DEBUG_FEAT(x) fprintf(ttyout, "features[" #x "] = %d\n", features[(x)]) - DEBUG_FEAT(FEAT_FEAT); - DEBUG_FEAT(FEAT_MDTM); - DEBUG_FEAT(FEAT_MLST); - DEBUG_FEAT(FEAT_REST_STREAM); - DEBUG_FEAT(FEAT_SIZE); - DEBUG_FEAT(FEAT_TVFS); -#undef DEBUG_FEAT - } - reply_callback = NULL; - - verbose = overbose; -} - -/* - * Reset the various variables that indicate connection state back to - * disconnected settings. - * The caller is responsible for issuing any commands to the remote server - * to perform a clean shutdown before this is invoked. - */ -void -cleanuppeer(void) -{ - - if (cout) - (void)fclose(cout); - cout = NULL; - connected = 0; - unix_server = 0; - unix_proxy = 0; - /* - * determine if anonftp was specifically set with -a - * (1), or implicitly set by auto_fetch() (2). in the - * latter case, disable after the current xfer - */ - if (anonftp == 2) - anonftp = 0; - data = -1; - epsv4bad = 0; - if (username) - free(username); - username = NULL; - if (!proxy) - macnum = 0; -} - -/* - * Top-level signal handler for interrupted commands. - */ -void -intr(int signo) -{ - - sigint_raised = 1; - alarmtimer(0); - if (fromatty) - write(fileno(ttyout), "\n", 1); - siglongjmp(toplevel, 1); -} - -/* - * Signal handler for lost connections; cleanup various elements of - * the connection state, and call cleanuppeer() to finish it off. - */ -void -lostpeer(int dummy) -{ - int oerrno = errno; - - alarmtimer(0); - if (connected) { - if (cout != NULL) { - (void)shutdown(fileno(cout), 1+1); - (void)fclose(cout); - cout = NULL; - } - if (data >= 0) { - (void)shutdown(data, 1+1); - (void)close(data); - data = -1; - } - connected = 0; - } - pswitch(1); - if (connected) { - if (cout != NULL) { - (void)shutdown(fileno(cout), 1+1); - (void)fclose(cout); - cout = NULL; - } - connected = 0; - } - proxflag = 0; - pswitch(0); - cleanuppeer(); - errno = oerrno; -} - - -/* - * Login to remote host, using given username & password if supplied. - * Return non-zero if successful. - */ -int -ftp_login(const char *host, const char *user, const char *pass) -{ - char tmp[80]; - const char *acct; - int n, aflag, rval, freeuser, freepass, freeacct; - - acct = NULL; - aflag = rval = freeuser = freepass = freeacct = 0; - - if (debug) - fprintf(ttyout, "ftp_login: user `%s' pass `%s' host `%s'\n", - user ? user : "<null>", pass ? pass : "<null>", - host ? host : "<null>"); - - - /* - * Set up arguments for an anonymous FTP session, if necessary. - */ - if (anonftp) { - user = "anonymous"; /* as per RFC 1635 */ - pass = getoptionvalue("anonpass"); - } - - if (user == NULL) - freeuser = 1; - if (pass == NULL) - freepass = 1; - freeacct = 1; - if (ruserpass(host, &user, &pass, &acct) < 0) { - code = -1; - goto cleanup_ftp_login; - } - - while (user == NULL) { - if (localname) - fprintf(ttyout, "Name (%s:%s): ", host, localname); - else - fprintf(ttyout, "Name (%s): ", host); - *tmp = '\0'; - if (fgets(tmp, sizeof(tmp) - 1, stdin) == NULL) { - fprintf(ttyout, "\nEOF received; login aborted.\n"); - clearerr(stdin); - code = -1; - goto cleanup_ftp_login; - } - tmp[strlen(tmp) - 1] = '\0'; - freeuser = 0; - if (*tmp == '\0') - user = localname; - else - user = tmp; - } - - if (gatemode) { - char *nuser; - int len; - - len = strlen(user) + 1 + strlen(host) + 1; - nuser = xmalloc(len); - (void)strlcpy(nuser, user, len); - (void)strlcat(nuser, "@", len); - (void)strlcat(nuser, host, len); - freeuser = 1; - user = nuser; - } - - n = command("USER %s", user); - if (n == CONTINUE) { - if (pass == NULL) { - freepass = 0; - pass = getpass("Password:"); - } - n = command("PASS %s", pass); - } - if (n == CONTINUE) { - aflag++; - if (acct == NULL) { - freeacct = 0; - acct = getpass("Account:"); - } - if (acct[0] == '\0') { - warnx("Login failed."); - goto cleanup_ftp_login; - } - n = command("ACCT %s", acct); - } - if ((n != COMPLETE) || - (!aflag && acct != NULL && command("ACCT %s", acct) != COMPLETE)) { - warnx("Login failed."); - goto cleanup_ftp_login; - } - rval = 1; - username = xstrdup(user); - if (proxy) - goto cleanup_ftp_login; - - connected = -1; - getremoteinfo(); - for (n = 0; n < macnum; ++n) { - if (!strcmp("init", macros[n].mac_name)) { - (void)strlcpy(line, "$init", sizeof(line)); - makeargv(); - domacro(margc, margv); - break; - } - } - updatelocalcwd(); - updateremotecwd(); - - cleanup_ftp_login: - if (user != NULL && freeuser) - free((char *)user); - if (pass != NULL && freepass) - free((char *)pass); - if (acct != NULL && freeacct) - free((char *)acct); - return (rval); -} - -/* - * `another' gets another argument, and stores the new argc and argv. - * It reverts to the top level (via intr()) on EOF/error. - * - * Returns false if no new arguments have been added. - */ -int -another(int *pargc, char ***pargv, const char *prompt) -{ - int len = strlen(line), ret; - - if (len >= sizeof(line) - 3) { - fputs("sorry, arguments too long.\n", ttyout); - intr(0); - } - fprintf(ttyout, "(%s) ", prompt); - line[len++] = ' '; - if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) { - clearerr(stdin); - intr(0); - } - len += strlen(&line[len]); - if (len > 0 && line[len - 1] == '\n') - line[len - 1] = '\0'; - makeargv(); - ret = margc > *pargc; - *pargc = margc; - *pargv = margv; - return (ret); -} - -/* - * glob files given in argv[] from the remote server. - * if errbuf isn't NULL, store error messages there instead - * of writing to the screen. - */ -char * -remglob(char *argv[], int doswitch, char **errbuf) -{ - char temp[MAXPATHLEN]; - static char buf[MAXPATHLEN]; - static FILE *ftemp = NULL; - static char **args; - int oldverbose, oldhash, oldprogress, fd, len; - char *cp, *mode; - - if (!mflag || !connected) { - if (!doglob) - args = NULL; - else { - if (ftemp) { - (void)fclose(ftemp); - ftemp = NULL; - } - } - return (NULL); - } - if (!doglob) { - if (args == NULL) - args = argv; - if ((cp = *++args) == NULL) - args = NULL; - return (cp); - } - if (ftemp == NULL) { - len = strlcpy(temp, tmpdir, sizeof(temp)); - if (temp[len - 1] != '/') - (void)strlcat(temp, "/", sizeof(temp)); - (void)strlcat(temp, TMPFILE, sizeof(temp)); - if ((fd = mkstemp(temp)) < 0) { - warn("unable to create temporary file %s", temp); - return (NULL); - } - close(fd); - oldverbose = verbose; - verbose = (errbuf != NULL) ? -1 : 0; - oldhash = hash; - oldprogress = progress; - hash = 0; - progress = 0; - if (doswitch) - pswitch(!proxy); - for (mode = "w"; *++argv != NULL; mode = "a") - recvrequest("NLST", temp, *argv, mode, 0, 0); - if ((code / 100) != COMPLETE) { - if (errbuf != NULL) - *errbuf = reply_string; - } - if (doswitch) - pswitch(!proxy); - verbose = oldverbose; - hash = oldhash; - progress = oldprogress; - ftemp = fopen(temp, "r"); - (void)unlink(temp); - if (ftemp == NULL) { - if (errbuf == NULL) - fputs( - "can't find list of remote files, oops.\n", - ttyout); - else - *errbuf = - "can't find list of remote files, oops."; - return (NULL); - } - } - if (fgets(buf, sizeof(buf), ftemp) == NULL) { - (void)fclose(ftemp); - ftemp = NULL; - return (NULL); - } - if ((cp = strchr(buf, '\n')) != NULL) - *cp = '\0'; - return (buf); -} - -/* - * Glob a local file name specification with the expectation of a single - * return value. Can't control multiple values being expanded from the - * expression, we return only the first. - * Returns NULL on error, or a pointer to a buffer containing the filename - * that's the caller's responsiblity to free(3) when finished with. - */ -char * -globulize(const char *pattern) -{ - glob_t gl; - int flags; - char *p; - - if (!doglob) - return (xstrdup(pattern)); - - flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; - memset(&gl, 0, sizeof(gl)); - if (glob(pattern, flags, NULL, &gl) || gl.gl_pathc == 0) { - warnx("%s: not found", pattern); - globfree(&gl); - return (NULL); - } - p = xstrdup(gl.gl_pathv[0]); - globfree(&gl); - return (p); -} - -/* - * determine size of remote file - */ -off_t -remotesize(const char *file, int noisy) -{ - int overbose, r; - off_t size; - - overbose = verbose; - size = -1; - if (debug == 0) - verbose = -1; - if (! features[FEAT_SIZE]) { - if (noisy) - fprintf(ttyout, - "SIZE is not supported by remote server.\n"); - goto cleanup_remotesize; - } - r = command("SIZE %s", file); - if (r == COMPLETE) { - char *cp, *ep; - - cp = strchr(reply_string, ' '); - if (cp != NULL) { - cp++; - size = STRTOLL(cp, &ep, 10); - if (*ep != '\0' && !isspace((unsigned char)*ep)) - size = -1; - } - } else { - if (r == ERROR && code == 500 && features[FEAT_SIZE] == -1) - features[FEAT_SIZE] = 0; - if (noisy && debug == 0) { - fputs(reply_string, ttyout); - putc('\n', ttyout); - } - } - cleanup_remotesize: - verbose = overbose; - return (size); -} - -/* - * determine last modification time (in GMT) of remote file - */ -time_t -remotemodtime(const char *file, int noisy) -{ - int overbose, ocode, r; - time_t rtime; - - overbose = verbose; - ocode = code; - rtime = -1; - if (debug == 0) - verbose = -1; - if (! features[FEAT_MDTM]) { - if (noisy) - fprintf(ttyout, - "MDTM is not supported by remote server.\n"); - goto cleanup_parse_time; - } - r = command("MDTM %s", file); - if (r == COMPLETE) { - struct tm timebuf; - char *timestr, *frac; - int yy, mo, day, hour, min, sec; - - /* - * time-val = 14DIGIT [ "." 1*DIGIT ] - * YYYYMMDDHHMMSS[.sss] - * mdtm-response = "213" SP time-val CRLF / error-response - */ - timestr = reply_string + 4; - - /* - * parse fraction. - * XXX: ignored for now - */ - frac = strchr(timestr, '\r'); - if (frac != NULL) - *frac = '\0'; - frac = strchr(timestr, '.'); - if (frac != NULL) - *frac++ = '\0'; - if (strlen(timestr) == 15 && strncmp(timestr, "191", 3) == 0) { - /* - * XXX: Workaround for lame ftpd's that return - * `19100' instead of `2000' - */ - fprintf(ttyout, - "Y2K warning! Incorrect time-val `%s' received from server.\n", - timestr); - timestr++; - timestr[0] = '2'; - timestr[1] = '0'; - fprintf(ttyout, "Converted to `%s'\n", timestr); - } - if (strlen(timestr) != 14 || - sscanf(timestr, "%04d%02d%02d%02d%02d%02d", - &yy, &mo, &day, &hour, &min, &sec) != 6) { - bad_parse_time: - fprintf(ttyout, "Can't parse time `%s'.\n", timestr); - goto cleanup_parse_time; - } - memset(&timebuf, 0, sizeof(timebuf)); - timebuf.tm_sec = sec; - timebuf.tm_min = min; - timebuf.tm_hour = hour; - timebuf.tm_mday = day; - timebuf.tm_mon = mo - 1; - timebuf.tm_year = yy - TM_YEAR_BASE; - timebuf.tm_isdst = -1; - rtime = timegm(&timebuf); - if (rtime == -1) { - if (noisy || debug != 0) - goto bad_parse_time; - else - goto cleanup_parse_time; - } else if (debug) - fprintf(ttyout, "parsed date as: %s", ctime(&rtime)); - } else { - if (r == ERROR && code == 500 && features[FEAT_MDTM] == -1) - features[FEAT_MDTM] = 0; - if (noisy && debug == 0) { - fputs(reply_string, ttyout); - putc('\n', ttyout); - } - } - cleanup_parse_time: - verbose = overbose; - if (rtime == -1) - code = ocode; - return (rtime); -} - -/* - * Update global `localcwd', which contains the state of the local cwd - */ -void -updatelocalcwd(void) -{ - - if (getcwd(localcwd, sizeof(localcwd)) == NULL) - localcwd[0] = '\0'; - if (debug) - fprintf(ttyout, "got localcwd as `%s'\n", localcwd); -} - -/* - * Update global `remotecwd', which contains the state of the remote cwd - */ -void -updateremotecwd(void) -{ - int overbose, ocode, i; - char *cp; - - overbose = verbose; - ocode = code; - if (debug == 0) - verbose = -1; - if (command("PWD") != COMPLETE) - goto badremotecwd; - cp = strchr(reply_string, ' '); - if (cp == NULL || cp[0] == '\0' || cp[1] != '"') - goto badremotecwd; - cp += 2; - for (i = 0; *cp && i < sizeof(remotecwd) - 1; i++, cp++) { - if (cp[0] == '"') { - if (cp[1] == '"') - cp++; - else - break; - } - remotecwd[i] = *cp; - } - remotecwd[i] = '\0'; - if (debug) - fprintf(ttyout, "got remotecwd as `%s'\n", remotecwd); - goto cleanupremotecwd; - badremotecwd: - remotecwd[0]='\0'; - cleanupremotecwd: - verbose = overbose; - code = ocode; -} - -/* - * Ensure file is in or under dir. - * Returns 1 if so, 0 if not (or an error occurred). - */ -int -fileindir(const char *file, const char *dir) -{ - char realfile[PATH_MAX+1]; - size_t dirlen; - - if (realpath(file, realfile) == NULL) { - warn("Unable to determine real path of `%s'", file); - return 0; - } - if (realfile[0] != '/') /* relative result */ - return 1; - dirlen = strlen(dir); -#if 0 -printf("file %s realfile %s dir %s [%d]\n", file, realfile, dir, dirlen); -#endif - if (strncmp(realfile, dir, dirlen) == 0 && realfile[dirlen] == '/') - return 1; - return 0; -} - -/* - * List words in stringlist, vertically arranged - */ -void -list_vertical(StringList *sl) -{ - int i, j, w; - int columns, width, lines; - char *p; - - width = 0; - - for (i = 0 ; i < sl->sl_cur ; i++) { - w = strlen(sl->sl_str[i]); - if (w > width) - width = w; - } - width = (width + 8) &~ 7; - - columns = ttywidth / width; - if (columns == 0) - columns = 1; - lines = (sl->sl_cur + columns - 1) / columns; - for (i = 0; i < lines; i++) { - for (j = 0; j < columns; j++) { - p = sl->sl_str[j * lines + i]; - if (p) - fputs(p, ttyout); - if (j * lines + i + lines >= sl->sl_cur) { - putc('\n', ttyout); - break; - } - w = strlen(p); - while (w < width) { - w = (w + 8) &~ 7; - (void)putc('\t', ttyout); - } - } - } -} - -/* - * Update the global ttywidth value, using TIOCGWINSZ. - */ -void -setttywidth(int a) -{ - struct winsize winsize; - int oerrno = errno; - - if (ioctl(fileno(ttyout), TIOCGWINSZ, &winsize) != -1 && - winsize.ws_col != 0) - ttywidth = winsize.ws_col; - else - ttywidth = 80; - errno = oerrno; -} - -/* - * Change the rate limit up (SIGUSR1) or down (SIGUSR2) - */ -void -crankrate(int sig) -{ - - switch (sig) { - case SIGUSR1: - if (rate_get) - rate_get += rate_get_incr; - if (rate_put) - rate_put += rate_put_incr; - break; - case SIGUSR2: - if (rate_get && rate_get > rate_get_incr) - rate_get -= rate_get_incr; - if (rate_put && rate_put > rate_put_incr) - rate_put -= rate_put_incr; - break; - default: - err(1, "crankrate invoked with unknown signal: %d", sig); - } -} - - -/* - * Setup or cleanup EditLine structures - */ -#ifndef NO_EDITCOMPLETE -void -controlediting(void) -{ - if (editing && el == NULL && hist == NULL) { - HistEvent ev; - int editmode; - - el = el_init(getprogname(), stdin, ttyout, stderr); - /* init editline */ - hist = history_init(); /* init the builtin history */ - history(hist, &ev, H_SETSIZE, 100);/* remember 100 events */ - el_set(el, EL_HIST, history, hist); /* use history */ - - el_set(el, EL_EDITOR, "emacs"); /* default editor is emacs */ - el_set(el, EL_PROMPT, prompt); /* set the prompt functions */ - el_set(el, EL_RPROMPT, rprompt); - - /* add local file completion, bind to TAB */ - el_set(el, EL_ADDFN, "ftp-complete", - "Context sensitive argument completion", - complete); - el_set(el, EL_BIND, "^I", "ftp-complete", NULL); - el_source(el, NULL); /* read ~/.editrc */ - if ((el_get(el, EL_EDITMODE, &editmode) != -1) && editmode == 0) - editing = 0; /* the user doesn't want editing, - * so disable, and let statement - * below cleanup */ - else - el_set(el, EL_SIGNAL, 1); - } - if (!editing) { - if (hist) { - history_end(hist); - hist = NULL; - } - if (el) { - el_end(el); - el = NULL; - } - } -} -#endif /* !NO_EDITCOMPLETE */ - -/* - * Convert the string `arg' to an int, which may have an optional SI suffix - * (`b', `k', `m', `g'). Returns the number for success, -1 otherwise. - */ -int -strsuftoi(const char *arg) -{ - char *cp; - long val; - - if (!isdigit((unsigned char)arg[0])) - return (-1); - - val = strtol(arg, &cp, 10); - if (cp != NULL) { - if (cp[0] != '\0' && cp[1] != '\0') - return (-1); - switch (tolower((unsigned char)cp[0])) { - case '\0': - case 'b': - break; - case 'k': - val <<= 10; - break; - case 'm': - val <<= 20; - break; - case 'g': - val <<= 30; - break; - default: - return (-1); - } - } - if (val < 0 || val > INT_MAX) - return (-1); - - return (val); -} - -/* - * Set up socket buffer sizes before a connection is made. - */ -void -setupsockbufsize(int sock) -{ - - if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, - (void *)&sndbuf_size, sizeof(sndbuf_size)) == -1) - warn("unable to set sndbuf size %d", sndbuf_size); - - if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, - (void *)&rcvbuf_size, sizeof(rcvbuf_size)) == -1) - warn("unable to set rcvbuf size %d", rcvbuf_size); -} - -/* - * Copy characters from src into dst, \ quoting characters that require it - */ -void -ftpvis(char *dst, size_t dstlen, const char *src, size_t srclen) -{ - int di, si; - - for (di = si = 0; - src[si] != '\0' && di < dstlen && si < srclen; - di++, si++) { - switch (src[si]) { - case '\\': - case ' ': - case '\t': - case '\r': - case '\n': - case '"': - dst[di++] = '\\'; - if (di >= dstlen) - break; - /* FALLTHROUGH */ - default: - dst[di] = src[si]; - } - } - dst[di] = '\0'; -} - -/* - * Copy src into buf (which is len bytes long), expanding % sequences. - */ -void -formatbuf(char *buf, size_t len, const char *src) -{ - const char *p; - char *p2, *q; - int i, op, updirs, pdirs; - -#define ADDBUF(x) do { \ - if (i >= len - 1) \ - goto endbuf; \ - buf[i++] = (x); \ - } while (0) - - p = src; - for (i = 0; *p; p++) { - if (*p != '%') { - ADDBUF(*p); - continue; - } - p++; - - switch (op = *p) { - - case '/': - case '.': - case 'c': - p2 = connected ? remotecwd : ""; - updirs = pdirs = 0; - - /* option to determine fixed # of dirs from path */ - if (op == '.' || op == 'c') { - int skip; - - q = p2; - while (*p2) /* calc # of /'s */ - if (*p2++ == '/') - updirs++; - if (p[1] == '0') { /* print <x> or ... */ - pdirs = 1; - p++; - } - if (p[1] >= '1' && p[1] <= '9') { - /* calc # to skip */ - skip = p[1] - '0'; - p++; - } else - skip = 1; - - updirs -= skip; - while (skip-- > 0) { - while ((p2 > q) && (*p2 != '/')) - p2--; /* back up */ - if (skip && p2 > q) - p2--; - } - if (*p2 == '/' && p2 != q) - p2++; - } - - if (updirs > 0 && pdirs) { - if (i >= len - 5) - break; - if (op == '.') { - ADDBUF('.'); - ADDBUF('.'); - ADDBUF('.'); - } else { - ADDBUF('/'); - ADDBUF('<'); - if (updirs > 9) { - ADDBUF('9'); - ADDBUF('+'); - } else - ADDBUF('0' + updirs); - ADDBUF('>'); - } - } - for (; *p2; p2++) - ADDBUF(*p2); - break; - - case 'M': - case 'm': - for (p2 = connected && username ? username : "-"; - *p2 ; p2++) { - if (op == 'm' && *p2 == '.') - break; - ADDBUF(*p2); - } - break; - - case 'n': - for (p2 = connected ? username : "-"; *p2 ; p2++) - ADDBUF(*p2); - break; - - case '%': - ADDBUF('%'); - break; - - default: /* display unknown codes literally */ - ADDBUF('%'); - ADDBUF(op); - break; - - } - } - endbuf: - buf[i] = '\0'; -} - -/* - * Parse `port' into a TCP port number, defaulting to `defport' if `port' is - * an unknown service name. If defport != -1, print a warning upon bad parse. - */ -int -parseport(const char *port, int defport) -{ - int rv; - long nport; - char *p, *ep; - - p = xstrdup(port); - nport = strtol(p, &ep, 10); - if (*ep != '\0' && ep == p) { - struct servent *svp; - - svp = getservbyname(port, "tcp"); - if (svp == NULL) { - badparseport: - if (defport != -1) - warnx("Unknown port `%s', using port %d", - port, defport); - rv = defport; - } else - rv = ntohs(svp->s_port); - } else if (nport < 1 || nport > MAX_IN_PORT_T || *ep != '\0') - goto badparseport; - else - rv = nport; - free(p); - return (rv); -} - -/* - * Determine if given string is an IPv6 address or not. - * Return 1 for yes, 0 for no - */ -int -isipv6addr(const char *addr) -{ - int rv = 0; -#ifdef INET6 - struct addrinfo hints, *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET6; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(addr, "0", &hints, &res) != 0) - rv = 0; - else { - rv = 1; - freeaddrinfo(res); - } - if (debug) - fprintf(ttyout, "isipv6addr: got %d for %s\n", rv, addr); -#endif - return (rv == 1) ? 1 : 0; -} - - -/* - * Internal version of connect(2); sets socket buffer sizes first and - * supports a connection timeout using a non-blocking connect(2) with - * a poll(2). - * Socket fcntl flags are temporarily updated to include O_NONBLOCK; - * these will not be reverted on connection failure. - * Returns -1 upon failure (with errno set to the problem), or 0 on success. - */ -int -xconnect(int sock, const struct sockaddr *name, socklen_t namelen) -{ - int flags, rv, timeout, error; - socklen_t slen; - struct timeval endtime, now, td; - struct pollfd pfd[1]; - - setupsockbufsize(sock); - - if ((flags = fcntl(sock, F_GETFL, 0)) == -1) - return -1; /* get current socket flags */ - if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) - return -1; /* set non-blocking connect */ - - /* NOTE: we now must restore socket flags on successful exit */ - - pfd[0].fd = sock; - pfd[0].events = POLLIN|POLLOUT; - - if (quit_time > 0) { /* want a non default timeout */ - (void)gettimeofday(&endtime, NULL); - endtime.tv_sec += quit_time; /* determine end time */ - } - - rv = connect(sock, name, namelen); /* inititate the connection */ - if (rv == -1) { /* connection error */ - if (errno != EINPROGRESS) /* error isn't "please wait" */ - return -1; - - /* connect EINPROGRESS; wait */ - do { - if (quit_time > 0) { /* determine timeout */ - (void)gettimeofday(&now, NULL); - timersub(&endtime, &now, &td); - timeout = td.tv_sec * 1000 + td.tv_usec/1000; - if (timeout < 0) - timeout = 0; - } else { - timeout = INFTIM; - } - pfd[0].revents = 0; - rv = xpoll(pfd, 1, timeout); - /* loop until poll ! EINTR */ - } while (rv == -1 && errno == EINTR); - - if (rv == 0) { /* poll (connect) timed out */ - errno = ETIMEDOUT; - return -1; - } - - if (rv == -1) { /* poll error */ - return -1; - } else if (pfd[0].revents & (POLLIN|POLLOUT)) { - slen = sizeof(error); /* OK, or pending error */ - if (getsockopt(sock, SOL_SOCKET, SO_ERROR, - &error, &slen) == -1) - return -1; /* Solaris pending error */ - if (error != 0) { - errno = error; /* BSD pending error */ - return -1; - } - } else { - errno = EBADF; /* this shouldn't happen ... */ - return -1; - } - } - - if (fcntl(sock, F_SETFL, flags) == -1) /* restore socket flags */ - return -1; - return 0; -} - -/* - * Internal version of listen(2); sets socket buffer sizes first. - */ -int -xlisten(int sock, int backlog) -{ - - setupsockbufsize(sock); - return (listen(sock, backlog)); -} - -/* - * Internal version of poll(2), to allow reimplementation by select(2) - * on platforms without the former. - */ -int -xpoll(struct pollfd *fds, int nfds, int timeout) -{ - return poll(fds, nfds, timeout); -} - -/* - * malloc() with inbuilt error checking - */ -void * -xmalloc(size_t size) -{ - void *p; - - p = malloc(size); - if (p == NULL) - err(1, "Unable to allocate %ld bytes of memory", (long)size); - return (p); -} - -/* - * sl_init() with inbuilt error checking - */ -StringList * -xsl_init(void) -{ - StringList *p; - - p = sl_init(); - if (p == NULL) - err(1, "Unable to allocate memory for stringlist"); - return (p); -} - -/* - * sl_add() with inbuilt error checking - */ -void -xsl_add(StringList *sl, char *i) -{ - - if (sl_add(sl, i) == -1) - err(1, "Unable to add `%s' to stringlist", i); -} - -/* - * strdup() with inbuilt error checking - */ -char * -xstrdup(const char *str) -{ - char *s; - - if (str == NULL) - errx(1, "xstrdup() called with NULL argument"); - s = strdup(str); - if (s == NULL) - err(1, "Unable to allocate memory for string copy"); - return (s); -} |