version 1.22, 2001/03/06 06:11:18 |
version 1.22.2.1, 2001/03/12 15:44:16 |
|
|
#include "buffer.h" |
#include "buffer.h" |
#include "bufaux.h" |
#include "bufaux.h" |
#include "log.h" |
#include "log.h" |
#include "atomicio.h" |
|
|
|
static int argno = 1; /* Number of argument currently being parsed */ |
static int argno = 1; /* Number of argument currently being parsed */ |
|
|
|
|
int timeout = 5; |
int timeout = 5; |
|
|
int maxfd; |
int maxfd; |
#define MAXCON (maxfd - 10) |
#define maxcon (maxfd - 10) |
|
|
extern char *__progname; |
extern char *__progname; |
fd_set *read_wait; |
fd_set read_wait; |
size_t read_wait_size; |
|
int ncon; |
int ncon; |
|
|
/* |
/* |
|
|
void (*errfun) (const char *,...); |
void (*errfun) (const char *,...); |
} Linebuf; |
} Linebuf; |
|
|
Linebuf * |
static inline Linebuf * |
Linebuf_alloc(const char *filename, void (*errfun) (const char *,...)) |
Linebuf_alloc(const char *filename, void (*errfun) (const char *,...)) |
{ |
{ |
Linebuf *lb; |
Linebuf *lb; |
|
|
return (lb); |
return (lb); |
} |
} |
|
|
void |
static inline void |
Linebuf_free(Linebuf * lb) |
Linebuf_free(Linebuf * lb) |
{ |
{ |
fclose(lb->stream); |
fclose(lb->stream); |
|
|
xfree(lb); |
xfree(lb); |
} |
} |
|
|
void |
static inline void |
Linebuf_restart(Linebuf * lb) |
Linebuf_restart(Linebuf * lb) |
{ |
{ |
clearerr(lb->stream); |
clearerr(lb->stream); |
|
|
lb->lineno = 0; |
lb->lineno = 0; |
} |
} |
|
|
int |
static inline int |
Linebuf_lineno(Linebuf * lb) |
Linebuf_lineno(Linebuf * lb) |
{ |
{ |
return (lb->lineno); |
return (lb->lineno); |
} |
} |
|
|
char * |
static inline char * |
Linebuf_getline(Linebuf * lb) |
Linebuf_getline(Linebuf * lb) |
{ |
{ |
int n = 0; |
int n = 0; |
|
|
/* Read a line */ |
/* Read a line */ |
if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) { |
if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) { |
if (ferror(lb->stream) && lb->errfun) |
if (ferror(lb->stream) && lb->errfun) |
(*lb->errfun) ("%s: %s\n", lb->filename, |
(*lb->errfun) ("%s: %s\n", lb->filename, strerror(errno)); |
strerror(errno)); |
|
return (NULL); |
return (NULL); |
} |
} |
n = strlen(lb->buf); |
n = strlen(lb->buf); |
|
|
} |
} |
if (n != lb->size - 1) { |
if (n != lb->size - 1) { |
if (lb->errfun) |
if (lb->errfun) |
(*lb->errfun) ("%s: skipping incomplete last line\n", |
(*lb->errfun) ("%s: skipping incomplete last line\n", lb->filename); |
lb->filename); |
|
return (NULL); |
return (NULL); |
} |
} |
/* Double the buffer if we need more space */ |
/* Double the buffer if we need more space */ |
if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) { |
if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) { |
if (lb->errfun) |
if (lb->errfun) |
(*lb->errfun) ("linebuf (%s): realloc failed\n", |
(*lb->errfun) ("linebuf (%s): realloc failed\n", lb->filename); |
lb->filename); |
|
return (NULL); |
return (NULL); |
} |
} |
} |
} |
} |
} |
|
|
int |
static int |
fdlim_get(int hard) |
fdlim_get(int hard) |
{ |
{ |
struct rlimit rlfd; |
struct rlimit rlfd; |
|
|
if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) |
if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) |
return (-1); |
return (-1); |
if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) |
if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) |
|
|
return hard ? rlfd.rlim_max : rlfd.rlim_cur; |
return hard ? rlfd.rlim_max : rlfd.rlim_cur; |
} |
} |
|
|
int |
static int |
fdlim_set(int lim) |
fdlim_set(int lim) |
{ |
{ |
struct rlimit rlfd; |
struct rlimit rlfd; |
|
|
* separators. This is the same as the 4.4BSD strsep, but different from the |
* separators. This is the same as the 4.4BSD strsep, but different from the |
* one in the GNU libc. |
* one in the GNU libc. |
*/ |
*/ |
char * |
inline char * |
xstrsep(char **str, const char *delim) |
xstrsep(char **str, const char *delim) |
{ |
{ |
char *s, *e; |
char *s, *e; |
|
|
gettimeofday(&fdcon[s].c_tv, NULL); |
gettimeofday(&fdcon[s].c_tv, NULL); |
fdcon[s].c_tv.tv_sec += timeout; |
fdcon[s].c_tv.tv_sec += timeout; |
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); |
TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); |
FD_SET(s, read_wait); |
FD_SET(s, &read_wait); |
ncon++; |
ncon++; |
return (s); |
return (s); |
} |
} |
|
|
void |
void |
confree(int s) |
confree(int s) |
{ |
{ |
|
close(s); |
if (s >= maxfd || fdcon[s].c_status == CS_UNUSED) |
if (s >= maxfd || fdcon[s].c_status == CS_UNUSED) |
fatal("confree: attempt to free bad fdno %d", s); |
fatal("confree: attempt to free bad fdno %d", s); |
close(s); |
|
xfree(fdcon[s].c_namebase); |
xfree(fdcon[s].c_namebase); |
xfree(fdcon[s].c_output_name); |
xfree(fdcon[s].c_output_name); |
if (fdcon[s].c_status == CS_KEYS) |
if (fdcon[s].c_status == CS_KEYS) |
xfree(fdcon[s].c_data); |
xfree(fdcon[s].c_data); |
fdcon[s].c_status = CS_UNUSED; |
fdcon[s].c_status = CS_UNUSED; |
TAILQ_REMOVE(&tq, &fdcon[s], c_link); |
TAILQ_REMOVE(&tq, &fdcon[s], c_link); |
FD_CLR(s, read_wait); |
FD_CLR(s, &read_wait); |
ncon--; |
ncon--; |
} |
} |
|
|
|
|
void |
void |
congreet(int s) |
congreet(int s) |
{ |
{ |
char buf[80], *cp; |
char buf[80]; |
size_t bufsiz; |
int n; |
int n = 0; |
|
con *c = &fdcon[s]; |
con *c = &fdcon[s]; |
|
|
bufsiz = sizeof(buf); |
n = read(s, buf, sizeof(buf)); |
cp = buf; |
|
while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n' && *cp != '\r') |
|
cp++; |
|
if (n < 0) { |
if (n < 0) { |
if (errno != ECONNREFUSED) |
if (errno != ECONNREFUSED) |
error("read (%s): %s", c->c_name, strerror(errno)); |
error("read (%s): %s", c->c_name, strerror(errno)); |
conrecycle(s); |
conrecycle(s); |
return; |
return; |
} |
} |
if (*cp != '\n' && *cp != '\r') { |
if (buf[n - 1] != '\n') { |
error("%s: bad greeting", c->c_name); |
error("%s: bad greeting", c->c_name); |
confree(s); |
confree(s); |
return; |
return; |
} |
} |
*cp = '\0'; |
buf[n - 1] = '\0'; |
fprintf(stderr, "# %s %s\n", c->c_name, buf); |
fprintf(stderr, "# %s %s\n", c->c_name, buf); |
n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n"); |
n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n"); |
if (atomicio(write, s, buf, n) != n) { |
if (write(s, buf, n) != n) { |
error("write (%s): %s", c->c_name, strerror(errno)); |
error("write (%s): %s", c->c_name, strerror(errno)); |
confree(s); |
confree(s); |
return; |
return; |
|
|
void |
void |
conloop(void) |
conloop(void) |
{ |
{ |
fd_set *r, *e; |
fd_set r, e; |
struct timeval seltime, now; |
struct timeval seltime, now; |
int i; |
int i; |
con *c; |
con *c; |
|
|
gettimeofday(&now, NULL); |
gettimeofday(&now, NULL); |
c = tq.tqh_first; |
c = tq.tqh_first; |
|
|
if (c && (c->c_tv.tv_sec > now.tv_sec || |
if (c && |
(c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) { |
(c->c_tv.tv_sec > now.tv_sec || |
|
(c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) { |
seltime = c->c_tv; |
seltime = c->c_tv; |
seltime.tv_sec -= now.tv_sec; |
seltime.tv_sec -= now.tv_sec; |
seltime.tv_usec -= now.tv_usec; |
seltime.tv_usec -= now.tv_usec; |
|
|
} else |
} else |
seltime.tv_sec = seltime.tv_usec = 0; |
seltime.tv_sec = seltime.tv_usec = 0; |
|
|
r = xmalloc(read_wait_size); |
r = e = read_wait; |
memcpy(r, read_wait, read_wait_size); |
while (select(maxfd, &r, NULL, &e, &seltime) == -1 && |
e = xmalloc(read_wait_size); |
|
memcpy(e, read_wait, read_wait_size); |
|
|
|
while (select(maxfd, r, NULL, e, &seltime) == -1 && |
|
(errno == EAGAIN || errno == EINTR)) |
(errno == EAGAIN || errno == EINTR)) |
; |
; |
|
|
for (i = 0; i < maxfd; i++) { |
for (i = 0; i < maxfd; i++) |
if (FD_ISSET(i, e)) { |
if (FD_ISSET(i, &e)) { |
error("%s: exception!", fdcon[i].c_name); |
error("%s: exception!", fdcon[i].c_name); |
confree(i); |
confree(i); |
} else if (FD_ISSET(i, r)) |
} else if (FD_ISSET(i, &r)) |
conread(i); |
conread(i); |
} |
|
xfree(r); |
|
xfree(e); |
|
|
|
c = tq.tqh_first; |
c = tq.tqh_first; |
while (c && (c->c_tv.tv_sec < now.tv_sec || |
while (c && |
(c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) { |
(c->c_tv.tv_sec < now.tv_sec || |
|
(c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) { |
int s = c->c_fd; |
int s = c->c_fd; |
|
|
c = c->c_link.tqe_next; |
c = c->c_link.tqe_next; |
conrecycle(s); |
conrecycle(s); |
} |
} |
|
|
return (argv[argno++]); |
return (argv[argno++]); |
} else if (!strncmp(argv[argno], "-f", 2)) { |
} else if (!strncmp(argv[argno], "-f", 2)) { |
char *fname; |
char *fname; |
|
|
if (argv[argno][2]) |
if (argv[argno][2]) |
fname = &argv[argno++][2]; |
fname = &argv[argno++][2]; |
else if (++argno >= argc) { |
else if (++argno >= argc) { |
|
|
fname = NULL; |
fname = NULL; |
lb = Linebuf_alloc(fname, error); |
lb = Linebuf_alloc(fname, error); |
} else |
} else |
error("ignoring invalid/misplaced option `%s'", |
error("ignoring invalid/misplaced option `%s'", argv[argno++]); |
argv[argno++]); |
|
} else { |
} else { |
char *line; |
char *line; |
|
|
line = Linebuf_getline(lb); |
line = Linebuf_getline(lb); |
if (line) |
if (line) |
return (line); |
return (line); |
|
|
} |
} |
} |
} |
|
|
void |
static void |
usage(void) |
usage(void) |
{ |
{ |
fatal("usage: %s [-t timeout] { [--] host | -f file } ...", __progname); |
fatal("usage: %s [-t timeout] { [--] host | -f file } ...", __progname); |
|
|
fatal("%s: fdlim_get: bad value", __progname); |
fatal("%s: fdlim_get: bad value", __progname); |
if (maxfd > MAXMAXFD) |
if (maxfd > MAXMAXFD) |
maxfd = MAXMAXFD; |
maxfd = MAXMAXFD; |
if (MAXCON <= 0) |
if (maxcon <= 0) |
fatal("%s: not enough file descriptors", __progname); |
fatal("%s: not enough file descriptors", __progname); |
if (maxfd > fdlim_get(0)) |
if (maxfd > fdlim_get(0)) |
fdlim_set(maxfd); |
fdlim_set(maxfd); |
fdcon = xmalloc(maxfd * sizeof(con)); |
fdcon = xmalloc(maxfd * sizeof(con)); |
memset(fdcon, 0, maxfd * sizeof(con)); |
memset(fdcon, 0, maxfd * sizeof(con)); |
|
|
read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask); |
|
read_wait = xmalloc(read_wait_size); |
|
memset(read_wait, 0, read_wait_size); |
|
|
|
do { |
do { |
while (ncon < MAXCON) { |
while (ncon < maxcon) { |
char *name; |
char *name; |
|
|
host = nexthost(argc, argv); |
host = nexthost(argc, argv); |