Exemple #1
0
static int
bin_syswrite(char *nam, char **args, Options ops, UNUSED(int func))
{
    int outfd = 1, len, count, totcount;
    char *countvar = NULL;

    /* -o: output file descriptor if not stdout */
    if (OPT_ISSET(ops, 'o')) {
	outfd = getposint(OPT_ARG(ops, 'o'), nam);
	if (outfd < 0)
	    return 1;
    }

    /* -c: variable in which to store count of bytes written */
    if (OPT_ISSET(ops, 'c')) {
	countvar = OPT_ARG(ops, 'c');
	if (!isident(countvar)) {
	    zwarnnam(nam, "not an identifier: %s", countvar);
	    return 1;
	}
    }

    totcount = 0;
    unmetafy(*args, &len);
    while (len) {
	while ((count = write(outfd, *args, len)) < 0) {
	    if (errno != EINTR || errflag || retflag || breaks || contflag)
	    {
		if (countvar)
		    setiparam(countvar, totcount);
		return 2;
	    }
	}
	*args += count;
	totcount += count;
	len -= count;
    }
    if (countvar)
	setiparam(countvar, totcount);

    return 0;
}
Exemple #2
0
static int
reverse_strftime(char *nam, char **argv, char *scalar, int quiet)
{
#if defined(HAVE_STRPTIME) && defined(HAVE_MKTIME)
    struct tm tm;
    zlong mytime;
    char *endp;

    /*
     * Initialise all parameters to zero; there's no floating point
     * so memset() will do the trick.  The exception is that tm_isdst
     * is set to -1 which, if not overridden, will cause mktime()
     * to use the current timezone.  This is probably the best guess;
     * it's the one that will cause dates and times output by strftime
     * without the -r option and without an explicit timezone to be
     * converted back correctly.
     */
    (void)memset(&tm, 0, sizeof(tm));
    tm.tm_isdst = -1;
    endp = strptime(argv[1], argv[0], &tm);

    if (!endp) {
	/* Conversion failed completely. */
	if (!quiet)
	    zwarnnam(nam, "format not matched");
	return 1;
    }

    mytime = (zlong)mktime(&tm);

    if (scalar)
	setiparam(scalar, mytime);
    else {
	char buf[DIGBUFSIZE];
	convbase(buf, mytime, 10);
	printf("%s\n", buf);
    }

    if (*endp && !quiet) {
	/*
	 * Not everything in the input string was converted.
	 * This is probably benign, since the format has been satisfied,
	 * but issue a warning unless the quiet flag is set.
	 */
	zwarnnam(nam, "warning: input string not completely matched");
    }

    return 0;
#else
    if (!quiet)
	zwarnnam(nam, "not implemented on this system");
    return 2;
#endif
}
Exemple #3
0
Fichier : pcre.c Projet : Lujaw/zsh
static int
zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar,
		     char *substravar, int want_offset_pair, int matchedinarr,
		     int want_begin_end)
{
    char **captures, *match_all, **matches;
    char offset_all[50];
    int capture_start = 1;

    if (matchedinarr)
	capture_start = 0;
    if (matchvar == NULL)
	matchvar = "MATCH";
    if (substravar == NULL)
	substravar = "match";
    
    /* captures[0] will be entire matched string, [1] first substring */
    if (!pcre_get_substring_list(arg, ovec, ret, (const char ***)&captures)) {
	int nelem = arrlen(captures)-1;
	/* Set to the offsets of the complete match */
	if (want_offset_pair) {
	    sprintf(offset_all, "%d %d", ovec[0], ovec[1]);
	    setsparam("ZPCRE_OP", ztrdup(offset_all));
	}
	match_all = metafy(captures[0], -1, META_DUP);
	setsparam(matchvar, match_all);
	/*
	 * If we're setting match, mbegin, mend we only do
	 * so if there were parenthesised matches, for consistency
	 * (c.f. regex.c).
	 */
	if (!want_begin_end || nelem) {
	    char **x, **y;
	    y = &captures[capture_start];
	    matches = x = (char **) zalloc(sizeof(char *) * (arrlen(y) + 1));
	    do {
		if (*y)
		    *x++ = metafy(*y, -1, META_DUP);
		else
		    *x++ = NULL;
	    } while (*y++);
	    setaparam(substravar, matches);
	}

	if (want_begin_end) {
	    char *ptr = arg;
	    zlong offs = 0;

	    /* Count the characters before the match */
	    MB_METACHARINIT();
	    while (ptr < arg + ovec[0]) {
		offs++;
		ptr += MB_METACHARLEN(ptr);
	    }
	    setiparam("MBEGIN", offs + !isset(KSHARRAYS));
	    /* Add on the characters in the match */
	    while (ptr < arg + ovec[1]) {
		offs++;
		ptr += MB_METACHARLEN(ptr);
	    }
	    setiparam("MEND", offs + !isset(KSHARRAYS) - 1);
	    if (nelem) {
		char **mbegin, **mend, **bptr, **eptr;
		int i, *ipair;

		bptr = mbegin = zalloc(sizeof(char*)*(nelem+1));
		eptr = mend = zalloc(sizeof(char*)*(nelem+1));

		for (ipair = ovec + 2, i = 0;
		     i < nelem;
		     ipair += 2, i++, bptr++, eptr++)
		{
		    char buf[DIGBUFSIZE];
		    ptr = arg;
		    offs = 0;
		    /* Find the start offset */
		    MB_METACHARINIT();
		    while (ptr < arg + ipair[0]) {
			offs++;
			ptr += MB_METACHARLEN(ptr);
		    }
		    convbase(buf, offs + !isset(KSHARRAYS), 10);
		    *bptr = ztrdup(buf);
		    /* Continue to the end offset */
		    while (ptr < arg + ipair[1]) {
			offs++;
			ptr += MB_METACHARLEN(ptr);
		    }
		    convbase(buf, offs + !isset(KSHARRAYS) - 1, 10);
		    *eptr = ztrdup(buf);
		}
		*bptr = *eptr = NULL;

		setaparam("mbegin", mbegin);
		setaparam("mend", mend);
	    }
	}

	pcre_free_substring_list((const char **)captures);
    }

    return 0;
}
Exemple #4
0
static int
bin_sysread(char *nam, char **args, Options ops, UNUSED(int func))
{
    int infd = 0, outfd = -1, bufsize = SYSREAD_BUFSIZE, count;
    char *outvar = NULL, *countvar = NULL, *inbuf;

    /* -i: input file descriptor if not stdin */
    if (OPT_ISSET(ops, 'i')) {
	infd = getposint(OPT_ARG(ops, 'i'), nam);
	if (infd < 0)
	    return 1;
    }

    /* -o: output file descriptor, else store in REPLY */
    if (OPT_ISSET(ops, 'o')) {
	if (*args) {
	    zwarnnam(nam, "no argument allowed with -o");
	    return 1;
	}
	outfd = getposint(OPT_ARG(ops, 'o'), nam);
	if (outfd < 0)
	    return 1;
    }

    /* -s: buffer size if not default SYSREAD_BUFSIZE */
    if (OPT_ISSET(ops, 's')) {
	bufsize = getposint(OPT_ARG(ops, 's'), nam);
	if (bufsize < 0)
	    return 1;
    }

    /* -c: name of variable to store count of transferred bytes */
    if (OPT_ISSET(ops, 'c')) {
	countvar = OPT_ARG(ops, 'c');
	if (!isident(countvar)) {
	    zwarnnam(nam, "not an identifier: %s", countvar);
	    return 1;
	}
    }

    if (*args) {
	/*
	 * Variable in which to store result if doing a plain read.
	 * Default variable if not specified is REPLY.
	 * If writing, only stuff we couldn't write is stored here,
	 * no default in that case (we just discard it if no variable).
	 */
	outvar = *args;
	if (!isident(outvar)) {
	    zwarnnam(nam, "not an identifier: %s", outvar);
	    return 1;
	}
    }

    inbuf = zhalloc(bufsize);

#if defined(HAVE_POLL) || defined(HAVE_SELECT)
    /* -t: timeout */
    if (OPT_ISSET(ops, 't'))
    {
# ifdef HAVE_POLL
	struct pollfd poll_fd;
	mnumber to_mn;
	int to_int, ret;

	poll_fd.fd = infd;
	poll_fd.events = POLLIN;

	to_mn = matheval(OPT_ARG(ops, 't'));
	if (errflag)
	    return 1;
	if (to_mn.type == MN_FLOAT)
	    to_int = (int) (1000 * to_mn.u.d);
	else
	    to_int = 1000 * (int)to_mn.u.l;

	while ((ret = poll(&poll_fd, 1, to_int)) < 0) {
	    if (errno != EINTR || errflag || retflag || breaks || contflag)
		break;
	}
	if (ret <= 0) {
	    /* treat non-timeout error as error on read */
	    return ret ? 2 : 4;
	}
# else
	/* using select */
	struct timeval select_tv;
	fd_set fds;
	mnumber to_mn;
	int ret;

	FD_ZERO(&fds);
	FD_SET(infd, &fds);
	to_mn = matheval(OPT_ARG(ops, 't'));
	if (errflag)
	    return 1;

	if (to_mn.type == MN_FLOAT) {
	    select_tv.tv_sec = (int) to_mn.u.d;
	    select_tv.tv_usec =
		(int) ((to_mn.u.d - select_tv.tv_sec) * 1e6);
	} else {
	    select_tv.tv_sec = (int) to_mn.u.l;
	    select_tv.tv_usec = 0;
	}

	while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds,
			     NULL, NULL,&select_tv)) < 1) {
	    if (errno != EINTR || errflag || retflag || breaks || contflag)
		break;
	}
	if (ret <= 0) {
	    /* treat non-timeout error as error on read */
	    return ret ? 2 : 4;
	}
# endif
    }
#endif

    while ((count = read(infd, inbuf, bufsize)) < 0) {
	if (errno != EINTR || errflag || retflag || breaks || contflag)
	    break;
    }
    if (countvar)
	setiparam(countvar, count);
    if (count < 0)
	return 2;

    if (outfd >= 0) {
	if (!count)
	    return 5;
	while (count > 0) {
	    int ret;

	    ret = write(outfd, inbuf, count);
	    if (ret < 0) {
		if (errno == EINTR && !errflag &&
		    !retflag && !breaks && !contflag)
		    continue;
		if (outvar)
		    setsparam(outvar, metafy(inbuf, count, META_DUP));
		if (countvar)
		    setiparam(countvar, count);
		return 3;
	    }
	    inbuf += ret;
	    count -= ret;
	}
	return 0;
    }

    if (!outvar)
	    outvar = "REPLY";
    /* do this even if we read zero bytes */
    setsparam(outvar, metafy(inbuf, count, META_DUP));

    return count ? 0 : 5;
}
Exemple #5
0
static int
bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
{
    int cloexec = 1, unlock = 0, readlock = 0;
    time_t timeout = 0;
    char *fdvar = NULL;
#ifdef HAVE_FCNTL_H
    struct flock lck;
    int flock_fd, flags;
#endif

    while (*args && **args == '-') {
	int opt;
	char *optptr = *args + 1, *optarg;
	args++;
	if (!*optptr || !strcmp(optptr, "-"))
	    break;
	while ((opt = *optptr)) {
	    switch (opt) {
	    case 'e':
		/* keep lock on "exec" */
		cloexec = 0;
		break;

	    case 'f':
		/* variable for fd */
		if (optptr[1]) {
		    fdvar = optptr + 1;
		    optptr += strlen(fdvar) - 1;
		} else if (*args) {
		    fdvar = *args++;
		}
		if (fdvar == NULL || !isident(fdvar)) {
		    zwarnnam(nam, "flock: option %c requires a variable name",
			     opt);
		    return 1;
		}
		break;

	    case 'r':
		/* read lock rather than read-write lock */
		readlock = 1;
		break;

	    case 't':
		/* timeout in seconds */
		if (optptr[1]) {
		    optarg = optptr + 1;
		    optptr += strlen(optarg) - 1;
		} else if (!*args) {
		    zwarnnam(nam, "flock: option %c requires a numeric timeout",
			     opt);
		    return 1;
		} else {
		    optarg = *args++;
		}
		timeout = (time_t)mathevali(optarg);
		break;

	    case 'u':
		/* unlock: argument is fd */
		unlock = 1;
		break;

	    default:
		zwarnnam(nam, "flock: unknown option: %c", *optptr);
		return 1;
	    }
	    optptr++;
	}
    }


    if (!args[0]) {
	zwarnnam(nam, "flock: not enough arguments");
	return 1;
    }
    if (args[1]) {
	zwarnnam(nam, "flock: too many arguments");
	return 1;
    }

#ifdef HAVE_FCNTL_H
    if (unlock) {
	flock_fd = (int)mathevali(args[0]);
	if (zcloselockfd(flock_fd) < 0) {
	    zwarnnam(nam, "flock: file descriptor %d not in use for locking",
		     flock_fd);
	    return 1;
	}
	return 0;
    }

    if (readlock)
	flags = O_RDONLY | O_NOCTTY;
    else
	flags = O_RDWR | O_NOCTTY;
    if ((flock_fd = open(unmeta(args[0]), flags)) < 0) {
	zwarnnam(nam, "failed to open %s for writing: %e", args[0], errno);
	return 1;
    }
    flock_fd = movefd(flock_fd);
    if (flock_fd == -1)
	return 1;
#ifdef FD_CLOEXEC
    if (cloexec)
    {
	long fdflags = fcntl(flock_fd, F_GETFD, 0);
	if (fdflags != (long)-1)
	    fcntl(flock_fd, F_SETFD, fdflags | FD_CLOEXEC);
    }
#endif
    addlockfd(flock_fd, cloexec);

    lck.l_type = readlock ? F_RDLCK : F_WRLCK;
    lck.l_whence = SEEK_SET;
    lck.l_start = 0;
    lck.l_len = 0;  /* lock the whole file */

    if (timeout > 0) {
	time_t end = time(NULL) + (time_t)timeout;
	while (fcntl(flock_fd, F_SETLK, &lck) < 0) {
	    if (errflag)
		return 1;
	    if (errno != EINTR && errno != EACCES && errno != EAGAIN) {
		zwarnnam(nam, "failed to lock file %s: %e", args[0], errno);
		return 1;
	    }
	    if (time(NULL) >= end)
		return 2;
	    sleep(1);
	}
    } else {
	while (fcntl(flock_fd, F_SETLKW, &lck) < 0) {
	    if (errflag)
		return 1;
	    if (errno == EINTR)
		continue;
	    zwarnnam(nam, "failed to lock file %s: %e", args[0], errno);
	    return 1;
	}
    }

    if (fdvar)
	setiparam(fdvar, flock_fd);

    return 0;
#else /* HAVE_FCNTL_H */
    zwarnnam(nam, "flock: not implemented on this system");
    return 255;
#endif /* HAVE_FCNTL_H */
}
Exemple #6
0
static int
zcond_regex_match(char **a, int id)
{
    regex_t re;
    regmatch_t *m, *matches = NULL;
    size_t matchessz = 0;
    char *lhstr, *lhstr_zshmeta, *rhre, *rhre_zshmeta, *s, **arr, **x;
    int r, n, return_value, rcflags, reflags, nelem, start;

    lhstr_zshmeta = cond_str(a,0,0);
    rhre_zshmeta = cond_str(a,1,0);
    rcflags = reflags = 0;
    return_value = 0; /* 1 => matched successfully */

    lhstr = ztrdup(lhstr_zshmeta);
    unmetafy(lhstr, NULL);
    rhre = ztrdup(rhre_zshmeta);
    unmetafy(rhre, NULL);

    switch(id) {
    case ZREGEX_EXTENDED:
	rcflags |= REG_EXTENDED;
	if (!isset(CASEMATCH))
	    rcflags |= REG_ICASE;
	r = regcomp(&re, rhre, rcflags);
	if (r) {
	    zregex_regerrwarn(r, &re, "failed to compile regex");
	    break;
	}
	/* re.re_nsub is number of parenthesized groups, we also need
	 * 1 for the 0 offset, which is the entire matched portion
	 */
	if ((int)re.re_nsub < 0) {
	    zwarn("INTERNAL ERROR: regcomp() returned "
		    "negative subpattern count %d", (int)re.re_nsub);
	    break;
	}
	matchessz = (re.re_nsub + 1) * sizeof(regmatch_t);
	matches = zalloc(matchessz);
	r = regexec(&re, lhstr, re.re_nsub+1, matches, reflags);
	if (r == REG_NOMATCH)
	    ; /* We do nothing when we fail to match. */
	else if (r == 0) {
	    return_value = 1;
	    if (isset(BASHREMATCH)) {
		start = 0;
		nelem = re.re_nsub + 1;
	    } else {
		start = 1;
		nelem = re.re_nsub;
	    }
	    arr = NULL; /* bogus gcc warning of used uninitialised */
	    /* entire matched portion + re_nsub substrings + NULL */
	    if (nelem) {
		arr = x = (char **) zalloc(sizeof(char *) * (nelem + 1));
		for (m = matches + start, n = start; n <= (int)re.re_nsub; ++n, ++m, ++x) {
		    *x = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP);
		}
		*x = NULL;
	    }
	    if (isset(BASHREMATCH)) {
		setaparam("BASH_REMATCH", arr);
	    } else {
		zlong offs;
		char *ptr;
		int clen, leftlen;

		m = matches;
		s = metafy(lhstr + m->rm_so, m->rm_eo - m->rm_so, META_DUP);
		setsparam("MATCH", s);
		/*
		 * Count the characters before the match.
		 */
		ptr = lhstr;
		leftlen = m->rm_so;
		offs = 0;
		MB_CHARINIT();
		while (leftlen) {
		    offs++;
		    clen = MB_CHARLEN(ptr, leftlen);
		    ptr += clen;
		    leftlen -= clen;
		}
		setiparam("MBEGIN", offs + !isset(KSHARRAYS));
		/*
		 * Add on the characters in the match.
		 */
		leftlen = m->rm_eo - m->rm_so;
		while (leftlen) {
		    offs++;
		    clen = MB_CHARLEN(ptr, leftlen);
		    ptr += clen;
		    leftlen -= clen;
		}
		setiparam("MEND", offs + !isset(KSHARRAYS) - 1);
		if (nelem) {
		    char **mbegin, **mend, **bptr, **eptr;
		    bptr = mbegin = (char **)zalloc(sizeof(char *)*(nelem+1));
		    eptr = mend = (char **)zalloc(sizeof(char *)*(nelem+1));

		    for (m = matches + start, n = 0;
			 n < nelem;
			 ++n, ++m, ++bptr, ++eptr)
		    {
			char buf[DIGBUFSIZE];
			if (m->rm_so < 0 || m->rm_eo < 0) {
			    *bptr = ztrdup("-1");
			    *eptr = ztrdup("-1");
			    continue;
			}
			ptr = lhstr;
			leftlen = m->rm_so;
			offs = 0;
			/* Find the start offset */
			MB_CHARINIT();
			while (leftlen) {
			    offs++;
			    clen = MB_CHARLEN(ptr, leftlen);
			    ptr += clen;
			    leftlen -= clen;
			}
			convbase(buf, offs + !isset(KSHARRAYS), 10);
			*bptr = ztrdup(buf);
			/* Continue to the end offset */
			leftlen = m->rm_eo - m->rm_so;
			while (leftlen ) {
			    offs++;
			    clen = MB_CHARLEN(ptr, leftlen);
			    ptr += clen;
			    leftlen -= clen;
			}
			convbase(buf, offs + !isset(KSHARRAYS) - 1, 10);
			*eptr = ztrdup(buf);
		    }
		    *bptr = *eptr = NULL;

		    setaparam("match", arr);
		    setaparam("mbegin", mbegin);
		    setaparam("mend", mend);
		}
	    }
	}
	else
	    zregex_regerrwarn(r, &re, "regex matching error");
	break;
    default:
	DPUTS(1, "bad regex option");
	return_value = 0;
	goto CLEAN_BASEMETA;
    }

    if (matches)
	zfree(matches, matchessz);
    regfree(&re);
CLEAN_BASEMETA:
    free(lhstr);
    free(rhre);
    return return_value;
}
Exemple #7
0
static int
bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func))
{
    int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0;
    ZSOCKLEN_T  len;
    char **addrp, *desthost, *localname, *remotename;
    struct hostent *zthost = NULL, *ztpeer = NULL;
    struct servent *srv;
    Tcp_session sess = NULL;

    if (OPT_ISSET(ops,'f'))
	force = 1;

    if (OPT_ISSET(ops,'v'))
	verbose = 1;

    if (OPT_ISSET(ops,'t'))
        test = 1;

    if (OPT_ISSET(ops,'d')) {
	targetfd = atoi(OPT_ARG(ops,'d'));
	if (!targetfd) {
	    zwarnnam(nam, "%s is an invalid argument to -d", OPT_ARG(ops,'d'));
	    return 1;
	}
    }


    if (OPT_ISSET(ops,'c')) {
	if (!args[0]) {
	    tcp_cleanup();
	}
	else {
	    targetfd = atoi(args[0]);
	    sess = zts_byfd(targetfd);
	    if(!targetfd) {
		zwarnnam(nam, "%s is an invalid argument to -c", args[0]);
		return 1;
	    }

	    if (sess)
	    {
		if ((sess->flags & ZTCP_ZFTP) && !force)
		{
		    zwarnnam(nam, "use -f to force closure of a zftp control connection");
		    return 1;
		}
		tcp_close(sess);
		return 0;
	    }
	    else
	    {
		zwarnnam(nam, "fd %s not found in tcp table", args[0]);
		return 1;
	    }
	}
    }
    else if (OPT_ISSET(ops,'l')) {
	int lport = 0;

	if (!args[0]) {
	    zwarnnam(nam, "-l requires an argument");
	    return 1;
	}

	srv = getservbyname(args[0], "tcp");
	if (srv)
	    lport = srv->s_port;
	else
	    lport = htons(atoi(args[0]));
	if (!lport) { zwarnnam(nam, "bad service name or port number");
	return 1;
	}
	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN);

	if (!sess) {
	    zwarnnam(nam, "unable to allocate a TCP session slot");
	    return 1;
	}
#ifdef SO_OOBINLINE
	len = 1;
	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
#endif
	if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr)))
	{
	    zwarnnam(nam, "bad address: %s", "0.0.0.0");
	    return 1;
	}

	sess->sock.in.sin_family = AF_INET;
	sess->sock.in.sin_port = lport;


	if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in)))
	{
	    char buf[DIGBUFSIZE];
	    convbase(buf, (zlong)ntohs(lport), 10);
	    zwarnnam(nam, "could not bind to port %s: %e", buf, errno);
	    tcp_close(sess);
	    return 1;
	}

	if (listen(sess->fd, 1))
	{
	    zwarnnam(nam, "could not listen on socket: %e", errno);
	    tcp_close(sess);
	    return 1;
	}

	if (targetfd) {
	    sess->fd = redup(sess->fd, targetfd);
	}
	else {
	    /* move the fd since no one will want to read from it */
	    sess->fd = movefd(sess->fd);
	}

	if (sess->fd == -1) {
	    zwarnnam(nam, "cannot duplicate fd %d: %e", sess->fd, errno);
	    tcp_close(sess);
	    return 1;
	}

	setiparam("REPLY", sess->fd);

	if (verbose)
	    printf("%d listener is on fd %d\n", ntohs(sess->sock.in.sin_port), sess->fd);

	return 0;

    }
    else if (OPT_ISSET(ops,'a'))
    {
	int lfd, rfd;

	if (!args[0]) {
	    zwarnnam(nam, "-a requires an argument");
	    return 1;
	}

	lfd = atoi(args[0]);

	if (!lfd) {
	    zwarnnam(nam, "invalid numerical argument");
	    return 1;
	}

	sess = zts_byfd(lfd);
	if (!sess) {
	    zwarnnam(nam, "fd %s is not registered as a tcp connection", args[0]);
	    return 1;
	}

	if (!(sess->flags & ZTCP_LISTEN))
	{
	    zwarnnam(nam, "tcp connection not a listener");
	    return 1;
	}

	if (test) {
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
# ifdef HAVE_POLL
	    struct pollfd pfd;
	    int ret;

	    pfd.fd = lfd;
	    pfd.events = POLLIN;
	    if ((ret = poll(&pfd, 1, 0)) == 0) return 1;
	    else if (ret == -1)
	    {
		zwarnnam(nam, "poll error: %e", errno);
		return 1;
	    }
# else
	    fd_set rfds;
	    struct timeval tv;
	    int ret;
	    
	    FD_ZERO(&rfds);
	    FD_SET(lfd, &rfds);
	    tv.tv_sec = 0;
	    tv.tv_usec = 0;
	    
	    if ((ret = select(lfd+1, &rfds, NULL, NULL, &tv)) == 0) return 1;
	    else if (ret == -1)
	    {
		zwarnnam(nam, "select error: %e", errno);
		return 1;
	    }
	    
# endif
	    
#else
	    zwarnnam(nam, "not currently supported");
	    return 1;
#endif
	}
	sess = zts_alloc(ZTCP_INBOUND);

	len = sizeof(sess->peer.in);
	if ((rfd = accept(lfd, (struct sockaddr *)&sess->peer.in, &len)) == -1)
	{
	    zwarnnam(nam, "could not accept connection: %e", errno);
	    tcp_close(sess);
	    return 1;
	}

	if (targetfd) {
	    sess->fd = redup(rfd, targetfd);
	    if (sess->fd < 0) {
		zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
		return 1;
	    }
	}
	else {
	    sess->fd = rfd;
	}

	setiparam("REPLY", sess->fd);

	if (verbose)
	    printf("%d is on fd %d\n", ntohs(sess->peer.in.sin_port), sess->fd);
    }
    else
    {
	if (!args[0]) {
	    LinkNode node;
	    for(node = firstnode(ztcp_sessions); node; incnode(node))
	    {
		sess = (Tcp_session)getdata(node);

		if (sess->fd != -1)
		{
		    zthost = gethostbyaddr((const void *)&(sess->sock.in.sin_addr), sizeof(sess->sock.in.sin_addr), AF_INET);
		    if (zthost)
			localname = zthost->h_name;
		    else
			localname = inet_ntoa(sess->sock.in.sin_addr);
		    ztpeer = gethostbyaddr((const void *)&(sess->peer.in.sin_addr), sizeof(sess->peer.in.sin_addr), AF_INET);
		    if (ztpeer)
			remotename = ztpeer->h_name;
		    else
			remotename = inet_ntoa(sess->peer.in.sin_addr);
		    if (OPT_ISSET(ops,'L')) {
			int schar;
			if (sess->flags & ZTCP_ZFTP)
			    schar = 'Z';
			else if (sess->flags & ZTCP_LISTEN)
			    schar = 'L';
			else if (sess->flags & ZTCP_INBOUND)
			    schar = 'I';
			else
			    schar = 'O';
			printf("%d %c %s %d %s %d\n",
			       sess->fd, schar,
			       localname, ntohs(sess->sock.in.sin_port),
			       remotename, ntohs(sess->peer.in.sin_port));
		    } else {
			printf("%s:%d %s %s:%d is on fd %d%s\n",
			       localname, ntohs(sess->sock.in.sin_port),
			       ((sess->flags & ZTCP_LISTEN) ? "-<" :
				((sess->flags & ZTCP_INBOUND) ? "<-" : "->")),
			       remotename, ntohs(sess->peer.in.sin_port),
			       sess->fd,
			       (sess->flags & ZTCP_ZFTP) ? " ZFTP" : "");
		    }
		}
	    }
	    return 0;
	}
	else if (!args[1]) {
	    destport = htons(23);
	}
	else {

	    srv = getservbyname(args[1],"tcp");
	    if (srv)
		destport = srv->s_port;
	    else
		destport = htons(atoi(args[1]));
	}
	
	desthost = ztrdup(args[0]);
	
	zthost = zsh_getipnodebyname(desthost, AF_INET, 0, &herrno);
	if (!zthost || errflag) {
	    zwarnnam(nam, "host resolution failure: %s", desthost);
	    zsfree(desthost);
	    return 1;
	}
	
	sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0);

	if (!sess) {
	    zwarnnam(nam, "unable to allocate a TCP session slot");
	    zsfree(desthost);
	    return 1;
	}

#ifdef SO_OOBINLINE
	len = 1;
	setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len));
#endif

	if (sess->fd < 0) {
	    zwarnnam(nam, "socket creation failed: %e", errno);
	    zsfree(desthost);
	    zts_delete(sess);
	    return 1;
	}
	
	for (addrp = zthost->h_addr_list; err && *addrp; addrp++) {
	    if (zthost->h_length != 4)
		zwarnnam(nam, "address length mismatch");
	    do {
		err = tcp_connect(sess, *addrp, zthost, destport);
	    } while (err && errno == EINTR && !errflag);
	}
	
	if (err) {
	    zwarnnam(nam, "connection failed: %e", errno);
	    tcp_close(sess);
	    zsfree(desthost);
	    return 1;
	}
	else
	{
	    if (targetfd) {
		sess->fd = redup(sess->fd, targetfd);
		if (sess->fd < 0) {
		    zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno);
		    zsfree(desthost);
		    tcp_close(sess);
		    return 1;
		}
	    }

	    setiparam("REPLY", sess->fd);

	    if (verbose)
		printf("%s:%d is now on fd %d\n",
			desthost, destport, sess->fd);
	}
	
	zsfree(desthost);
    }

    return 0;
}