mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Factor out common code from Unix CLI main loops.
Unix Plink, Unix Pageant in server mode, Uppity, and the post- connection form of PSFTP's command-line reading code all had very similar loops in them, which run a pollwrapper and mediate between that, timers, and toplevel callbacks. It's long past time the common code between all of those became a reusable shared routine. So, this commit introduces uxcliloop.c, and turns all the previous copies of basically the same loop into a call to cli_main_loop with various callback functions to configure the parts that differ.
This commit is contained in:
parent
78974fce89
commit
586dc96f5f
10
Recipe
10
Recipe
@ -364,7 +364,7 @@ puttytel : [X] GTKTERM uxmisc misc ldisc settings uxsel U_BE_NOSSH
|
|||||||
+ nogss utils memory GTKMAIN
|
+ nogss utils memory GTKMAIN
|
||||||
|
|
||||||
plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal
|
plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal
|
||||||
+ ux_x11 noterm uxnogtk sessprep cmdline clicons
|
+ ux_x11 noterm uxnogtk sessprep cmdline clicons uxcliloop
|
||||||
|
|
||||||
PUTTYGEN_UNIX = KEYGEN sshprime sshdes ARITH sshmd5 version sshprng
|
PUTTYGEN_UNIX = KEYGEN sshprime sshdes ARITH sshmd5 version sshprng
|
||||||
+ sshrand uxnoise sshsha MISC sshrsa sshdss uxcons uxstore uxmisc
|
+ sshrand uxnoise sshsha MISC sshrsa sshdss uxcons uxstore uxmisc
|
||||||
@ -375,15 +375,15 @@ puttygen : [U] cmdgen PUTTYGEN_UNIX
|
|||||||
cgtest : [UT] cgtest PUTTYGEN_UNIX
|
cgtest : [UT] cgtest PUTTYGEN_UNIX
|
||||||
|
|
||||||
pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk
|
pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk
|
||||||
+ clicons
|
+ clicons uxcliloop
|
||||||
psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk
|
psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC uxnogtk
|
||||||
+ clicons
|
+ clicons uxcliloop
|
||||||
|
|
||||||
pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes ARITH
|
pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes ARITH
|
||||||
+ sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512
|
+ sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512
|
||||||
+ sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons
|
+ sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons
|
||||||
+ gtkask gtkmisc nullplug logging UXMISC uxagentsock utils memory
|
+ gtkask gtkmisc nullplug logging UXMISC uxagentsock utils memory
|
||||||
+ sshauxcrypt sshhmac sshprng uxnoise
|
+ sshauxcrypt sshhmac sshprng uxnoise uxcliloop
|
||||||
|
|
||||||
ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
|
ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
|
||||||
+ uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg
|
+ uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg
|
||||||
@ -404,7 +404,7 @@ testsc : [UT] testsc SSHCRYPTO marshal utils memory tree234 wildcard
|
|||||||
testzlib : [UT] testzlib sshzlib utils marshal memory
|
testzlib : [UT] testzlib sshzlib utils marshal memory
|
||||||
|
|
||||||
uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk
|
uppity : [UT] uxserver SSHSERVER UXMISC uxsignal uxnoise uxgss uxnogtk
|
||||||
+ uxpty uxsftpserver ux_x11 uxagentsock procnet
|
+ uxpty uxsftpserver ux_x11 uxagentsock procnet uxcliloop
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# On Windows, provide a means of removing local test binaries that we
|
# On Windows, provide a means of removing local test binaries that we
|
||||||
|
16
unix/unix.h
16
unix/unix.h
@ -444,4 +444,20 @@ static inline bool pollwrap_check_fd_rwx(pollwrapper *pw, int fd, int rwx)
|
|||||||
return (pollwrap_get_fd_rwx(pw, fd) & rwx) != 0;
|
return (pollwrap_get_fd_rwx(pw, fd) & rwx) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* uxcliloop.c.
|
||||||
|
*/
|
||||||
|
typedef bool (*cliloop_pw_setup_t)(void *ctx, pollwrapper *pw);
|
||||||
|
typedef void (*cliloop_pw_check_t)(void *ctx, pollwrapper *pw);
|
||||||
|
typedef bool (*cliloop_continue_t)(void *ctx, bool found_any_fd,
|
||||||
|
bool ran_any_callback);
|
||||||
|
|
||||||
|
void cli_main_loop(cliloop_pw_setup_t pw_setup,
|
||||||
|
cliloop_pw_check_t pw_check,
|
||||||
|
cliloop_continue_t cont, void *ctx);
|
||||||
|
|
||||||
|
bool cliloop_no_pw_setup(void *ctx, pollwrapper *pw);
|
||||||
|
void cliloop_no_pw_check(void *ctx, pollwrapper *pw);
|
||||||
|
bool cliloop_always_continue(void *ctx, bool, bool);
|
||||||
|
|
||||||
#endif /* PUTTY_UNIX_H */
|
#endif /* PUTTY_UNIX_H */
|
||||||
|
125
unix/uxcliloop.c
Normal file
125
unix/uxcliloop.c
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "putty.h"
|
||||||
|
|
||||||
|
void cli_main_loop(cliloop_pw_setup_t pw_setup,
|
||||||
|
cliloop_pw_check_t pw_check,
|
||||||
|
cliloop_continue_t cont, void *ctx)
|
||||||
|
{
|
||||||
|
unsigned long now = GETTICKCOUNT();
|
||||||
|
|
||||||
|
int *fdlist = NULL;
|
||||||
|
size_t fdsize = 0;
|
||||||
|
|
||||||
|
pollwrapper *pw = pollwrap_new();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int rwx;
|
||||||
|
int ret;
|
||||||
|
int fdstate;
|
||||||
|
unsigned long next;
|
||||||
|
|
||||||
|
pollwrap_clear(pw);
|
||||||
|
|
||||||
|
if (!pw_setup(ctx, pw))
|
||||||
|
break; /* our client signalled emergency exit */
|
||||||
|
|
||||||
|
/* Count the currently active fds. */
|
||||||
|
size_t nfds = 0;
|
||||||
|
for (int fd = first_fd(&fdstate, &rwx); fd >= 0;
|
||||||
|
fd = next_fd(&fdstate, &rwx))
|
||||||
|
nfds++;
|
||||||
|
|
||||||
|
/* Expand the fdlist buffer if necessary. */
|
||||||
|
sgrowarray(fdlist, fdsize, nfds);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add all currently open uxsel fds to pw, and store them in
|
||||||
|
* fdlist as well.
|
||||||
|
*/
|
||||||
|
size_t fdcount = 0;
|
||||||
|
for (int fd = first_fd(&fdstate, &rwx); fd >= 0;
|
||||||
|
fd = next_fd(&fdstate, &rwx)) {
|
||||||
|
fdlist[fdcount++] = fd;
|
||||||
|
pollwrap_add_fd_rwx(pw, fd, rwx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toplevel_callback_pending()) {
|
||||||
|
ret = pollwrap_poll_instant(pw);
|
||||||
|
} else if (run_timers(now, &next)) {
|
||||||
|
do {
|
||||||
|
unsigned long then;
|
||||||
|
long ticks;
|
||||||
|
|
||||||
|
then = now;
|
||||||
|
now = GETTICKCOUNT();
|
||||||
|
if (now - then > next - then)
|
||||||
|
ticks = 0;
|
||||||
|
else
|
||||||
|
ticks = next - now;
|
||||||
|
|
||||||
|
bool overflow = false;
|
||||||
|
if (ticks > INT_MAX) {
|
||||||
|
ticks = INT_MAX;
|
||||||
|
overflow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pollwrap_poll_timeout(pw, ticks);
|
||||||
|
if (ret == 0 && !overflow)
|
||||||
|
now = next;
|
||||||
|
else
|
||||||
|
now = GETTICKCOUNT();
|
||||||
|
} while (ret < 0 && errno == EINTR);
|
||||||
|
} else {
|
||||||
|
ret = pollwrap_poll_endless(pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("poll");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found_fd = (ret > 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fdcount; i++) {
|
||||||
|
int fd = fdlist[i];
|
||||||
|
int rwx = pollwrap_get_fd_rwx(pw, fd);
|
||||||
|
/*
|
||||||
|
* We must process exceptional notifications before
|
||||||
|
* ordinary readability ones, or we may go straight
|
||||||
|
* past the urgent marker.
|
||||||
|
*/
|
||||||
|
if (rwx & SELECT_X)
|
||||||
|
select_result(fd, SELECT_X);
|
||||||
|
if (rwx & SELECT_R)
|
||||||
|
select_result(fd, SELECT_R);
|
||||||
|
if (rwx & SELECT_W)
|
||||||
|
select_result(fd, SELECT_W);
|
||||||
|
}
|
||||||
|
|
||||||
|
pw_check(ctx, pw);
|
||||||
|
|
||||||
|
bool ran_callback = run_toplevel_callbacks();
|
||||||
|
|
||||||
|
if (!cont(ctx, found_fd, ran_callback))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pollwrap_free(pw);
|
||||||
|
sfree(fdlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cliloop_no_pw_setup(void *ctx, pollwrapper *pw) { return true; }
|
||||||
|
void cliloop_no_pw_check(void *ctx, pollwrapper *pw) {}
|
||||||
|
bool cliloop_always_continue(void *ctx, bool fd, bool cb) { return true; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Any application using this main loop doesn't need to do anything
|
||||||
|
* when uxsel adds or removes an fd, because we synchronously re-check
|
||||||
|
* the current list every time we go round the main loop above.
|
||||||
|
*/
|
||||||
|
uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; }
|
||||||
|
void uxsel_input_remove(uxsel_id *id) { }
|
278
unix/uxpgnt.c
278
unix/uxpgnt.c
@ -35,6 +35,8 @@ struct uxpgnt_client {
|
|||||||
strbuf *debug_prompt_buf;
|
strbuf *debug_prompt_buf;
|
||||||
bool debug_prompt_active, debug_prompt_possible;
|
bool debug_prompt_active, debug_prompt_possible;
|
||||||
PageantClientDialogId *dlgid;
|
PageantClientDialogId *dlgid;
|
||||||
|
int passphrase_fd;
|
||||||
|
int termination_pid;
|
||||||
|
|
||||||
PageantListenerClient plc;
|
PageantListenerClient plc;
|
||||||
};
|
};
|
||||||
@ -92,13 +94,6 @@ static const PageantListenerClientVtable uxpgnt_vtable = {
|
|||||||
uxpgnt_ask_passphrase,
|
uxpgnt_ask_passphrase,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* In Pageant our selects are synchronous, so these functions are
|
|
||||||
* empty stubs.
|
|
||||||
*/
|
|
||||||
uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; }
|
|
||||||
void uxsel_input_remove(uxsel_id *id) { }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* More stubs.
|
* More stubs.
|
||||||
*/
|
*/
|
||||||
@ -776,6 +771,93 @@ static const PlugVtable X11Connection_plugvt = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static bool agent_loop_pw_setup(void *vctx, pollwrapper *pw)
|
||||||
|
{
|
||||||
|
struct uxpgnt_client *upc = (struct uxpgnt_client *)vctx;
|
||||||
|
|
||||||
|
if (signalpipe[0] >= 0) {
|
||||||
|
pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upc->debug_prompt_active)
|
||||||
|
pollwrap_add_fd_rwx(pw, upc->passphrase_fd, SELECT_R);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agent_loop_pw_check(void *vctx, pollwrapper *pw)
|
||||||
|
{
|
||||||
|
struct uxpgnt_client *upc = (struct uxpgnt_client *)vctx;
|
||||||
|
|
||||||
|
if (life == LIFE_TTY) {
|
||||||
|
/*
|
||||||
|
* Every time we wake up (whether it was due to tty_timer
|
||||||
|
* elapsing or for any other reason), poll to see if we still
|
||||||
|
* have a controlling terminal. If we don't, then our
|
||||||
|
* containing tty session has ended, so it's time to clean up
|
||||||
|
* and leave.
|
||||||
|
*/
|
||||||
|
if (!have_controlling_tty()) {
|
||||||
|
time_to_die = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signalpipe[0] >= 0 &&
|
||||||
|
pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
|
||||||
|
char c[1];
|
||||||
|
if (read(signalpipe[0], c, 1) <= 0)
|
||||||
|
/* ignore error */;
|
||||||
|
/* ignore its value; it'll be `x' */
|
||||||
|
while (1) {
|
||||||
|
int status;
|
||||||
|
pid_t pid;
|
||||||
|
pid = waitpid(-1, &status, WNOHANG);
|
||||||
|
if (pid <= 0)
|
||||||
|
break;
|
||||||
|
if (pid == upc->termination_pid)
|
||||||
|
time_to_die = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upc->debug_prompt_active &&
|
||||||
|
pollwrap_check_fd_rwx(pw, upc->passphrase_fd, SELECT_R)) {
|
||||||
|
char c;
|
||||||
|
int retd = read(upc->passphrase_fd, &c, 1);
|
||||||
|
if (retd <= 0) {
|
||||||
|
passphrase_done(upc, false);
|
||||||
|
/* Now never try to read from stdin again */
|
||||||
|
upc->debug_prompt_possible = false;
|
||||||
|
} else {
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
passphrase_done(upc, true);
|
||||||
|
break;
|
||||||
|
case '\004':
|
||||||
|
passphrase_done(upc, false);
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
case '\177':
|
||||||
|
strbuf_shrink_by(upc->debug_prompt_buf, 1);
|
||||||
|
break;
|
||||||
|
case '\025':
|
||||||
|
strbuf_clear(upc->debug_prompt_buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
put_byte(upc->debug_prompt_buf, c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool agent_loop_continue(void *vctx, bool fd, bool cb)
|
||||||
|
{
|
||||||
|
return !time_to_die;
|
||||||
|
}
|
||||||
|
|
||||||
void run_agent(FILE *logfp, const char *symlink_path)
|
void run_agent(FILE *logfp, const char *symlink_path)
|
||||||
{
|
{
|
||||||
const char *err;
|
const char *err;
|
||||||
@ -783,20 +865,10 @@ void run_agent(FILE *logfp, const char *symlink_path)
|
|||||||
struct pageant_listen_state *pl;
|
struct pageant_listen_state *pl;
|
||||||
Plug *pl_plug;
|
Plug *pl_plug;
|
||||||
Socket *sock;
|
Socket *sock;
|
||||||
unsigned long now;
|
|
||||||
int *fdlist;
|
|
||||||
int fd;
|
|
||||||
int i, fdstate;
|
|
||||||
size_t fdsize;
|
|
||||||
int passphrase_fd = -1;
|
|
||||||
int termination_pid = -1;
|
|
||||||
bool errors = false;
|
bool errors = false;
|
||||||
Conf *conf;
|
Conf *conf;
|
||||||
const struct cmdline_key_action *act;
|
const struct cmdline_key_action *act;
|
||||||
|
|
||||||
fdlist = NULL;
|
|
||||||
fdsize = 0;
|
|
||||||
|
|
||||||
pageant_init();
|
pageant_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -817,6 +889,8 @@ void run_agent(FILE *logfp, const char *symlink_path)
|
|||||||
memset(upc, 0, sizeof(upc));
|
memset(upc, 0, sizeof(upc));
|
||||||
upc->plc.vt = &uxpgnt_vtable;
|
upc->plc.vt = &uxpgnt_vtable;
|
||||||
upc->logfp = logfp;
|
upc->logfp = logfp;
|
||||||
|
upc->passphrase_fd = -1;
|
||||||
|
upc->termination_pid = -1;
|
||||||
pl = pageant_listener_new(&pl_plug, &upc->plc);
|
pl = pageant_listener_new(&pl_plug, &upc->plc);
|
||||||
sock = platform_make_agent_socket(pl_plug, PAGEANT_DIR_PREFIX,
|
sock = platform_make_agent_socket(pl_plug, PAGEANT_DIR_PREFIX,
|
||||||
&errw, &socketname);
|
&errw, &socketname);
|
||||||
@ -906,8 +980,8 @@ void run_agent(FILE *logfp, const char *symlink_path)
|
|||||||
upc->logfp = stdout;
|
upc->logfp = stdout;
|
||||||
|
|
||||||
struct termios orig_termios;
|
struct termios orig_termios;
|
||||||
passphrase_fd = fileno(stdin);
|
upc->passphrase_fd = fileno(stdin);
|
||||||
if (tcgetattr(passphrase_fd, &orig_termios) == 0) {
|
if (tcgetattr(upc->passphrase_fd, &orig_termios) == 0) {
|
||||||
struct termios new_termios = orig_termios;
|
struct termios new_termios = orig_termios;
|
||||||
new_termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
|
new_termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
|
||||||
|
|
||||||
@ -920,11 +994,11 @@ void run_agent(FILE *logfp, const char *symlink_path)
|
|||||||
if (pipe(pipefd) == 0) {
|
if (pipe(pipefd) == 0) {
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
tcsetattr(passphrase_fd, TCSADRAIN, &new_termios);
|
tcsetattr(upc->passphrase_fd, TCSADRAIN, &new_termios);
|
||||||
close(pipefd[1]);
|
close(pipefd[1]);
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
while (read(pipefd[0], buf, sizeof(buf)) > 0);
|
while (read(pipefd[0], buf, sizeof(buf)) > 0);
|
||||||
tcsetattr(passphrase_fd, TCSADRAIN, &new_termios);
|
tcsetattr(upc->passphrase_fd, TCSADRAIN, &new_termios);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
} else if (pid > 0) {
|
} else if (pid > 0) {
|
||||||
upc->debug_prompt_possible = true;
|
upc->debug_prompt_possible = true;
|
||||||
@ -961,170 +1035,18 @@ void run_agent(FILE *logfp, const char *symlink_path)
|
|||||||
perror("exec");
|
perror("exec");
|
||||||
_exit(127);
|
_exit(127);
|
||||||
} else {
|
} else {
|
||||||
termination_pid = pid;
|
upc->termination_pid = pid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!upc->logfp)
|
if (!upc->logfp)
|
||||||
upc->plc.suppress_logging = true;
|
upc->plc.suppress_logging = true;
|
||||||
|
|
||||||
now = GETTICKCOUNT();
|
cli_main_loop(agent_loop_pw_setup, agent_loop_pw_check,
|
||||||
|
agent_loop_continue, upc);
|
||||||
pollwrapper *pw = pollwrap_new();
|
|
||||||
|
|
||||||
while (!time_to_die) {
|
|
||||||
int rwx;
|
|
||||||
int ret;
|
|
||||||
unsigned long next;
|
|
||||||
|
|
||||||
pollwrap_clear(pw);
|
|
||||||
|
|
||||||
if (signalpipe[0] >= 0) {
|
|
||||||
pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Count the currently active fds. */
|
|
||||||
i = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) i++;
|
|
||||||
|
|
||||||
/* Expand the fdlist buffer if necessary. */
|
|
||||||
sgrowarray(fdlist, fdsize, i);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add all currently open fds to pw, and store them in fdlist
|
|
||||||
* as well.
|
|
||||||
*/
|
|
||||||
int fdcount = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) {
|
|
||||||
fdlist[fdcount++] = fd;
|
|
||||||
pollwrap_add_fd_rwx(pw, fd, rwx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (upc->debug_prompt_active)
|
|
||||||
pollwrap_add_fd_rwx(pw, passphrase_fd, SELECT_R);
|
|
||||||
|
|
||||||
if (toplevel_callback_pending()) {
|
|
||||||
ret = pollwrap_poll_instant(pw);
|
|
||||||
} else if (run_timers(now, &next)) {
|
|
||||||
unsigned long then;
|
|
||||||
long ticks;
|
|
||||||
|
|
||||||
then = now;
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
if (now - then > next - then)
|
|
||||||
ticks = 0;
|
|
||||||
else
|
|
||||||
ticks = next - now;
|
|
||||||
|
|
||||||
bool overflow = false;
|
|
||||||
if (ticks > INT_MAX) {
|
|
||||||
ticks = INT_MAX;
|
|
||||||
overflow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = pollwrap_poll_timeout(pw, ticks);
|
|
||||||
if (ret == 0 && !overflow)
|
|
||||||
now = next;
|
|
||||||
else
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
} else {
|
|
||||||
ret = pollwrap_poll_endless(pw);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0 && errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("poll");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (life == LIFE_TTY) {
|
|
||||||
/*
|
|
||||||
* Every time we wake up (whether it was due to tty_timer
|
|
||||||
* elapsing or for any other reason), poll to see if we
|
|
||||||
* still have a controlling terminal. If we don't, then
|
|
||||||
* our containing tty session has ended, so it's time to
|
|
||||||
* clean up and leave.
|
|
||||||
*/
|
|
||||||
if (!have_controlling_tty()) {
|
|
||||||
time_to_die = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < fdcount; i++) {
|
|
||||||
fd = fdlist[i];
|
|
||||||
int rwx = pollwrap_get_fd_rwx(pw, fd);
|
|
||||||
/*
|
|
||||||
* We must process exceptional notifications before
|
|
||||||
* ordinary readability ones, or we may go straight
|
|
||||||
* past the urgent marker.
|
|
||||||
*/
|
|
||||||
if (rwx & SELECT_X)
|
|
||||||
select_result(fd, SELECT_X);
|
|
||||||
if (rwx & SELECT_R)
|
|
||||||
select_result(fd, SELECT_R);
|
|
||||||
if (rwx & SELECT_W)
|
|
||||||
select_result(fd, SELECT_W);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signalpipe[0] >= 0 &&
|
|
||||||
pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
|
|
||||||
char c[1];
|
|
||||||
if (read(signalpipe[0], c, 1) <= 0)
|
|
||||||
/* ignore error */;
|
|
||||||
/* ignore its value; it'll be `x' */
|
|
||||||
while (1) {
|
|
||||||
int status;
|
|
||||||
pid_t pid;
|
|
||||||
pid = waitpid(-1, &status, WNOHANG);
|
|
||||||
if (pid <= 0)
|
|
||||||
break;
|
|
||||||
if (pid == termination_pid)
|
|
||||||
time_to_die = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (upc->debug_prompt_active &&
|
|
||||||
pollwrap_check_fd_rwx(pw, passphrase_fd, SELECT_R)) {
|
|
||||||
char c;
|
|
||||||
int retd = read(passphrase_fd, &c, 1);
|
|
||||||
if (retd <= 0) {
|
|
||||||
passphrase_done(upc, false);
|
|
||||||
/* Now never try to read from stdin again */
|
|
||||||
upc->debug_prompt_possible = false;
|
|
||||||
} else {
|
|
||||||
switch (c) {
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
passphrase_done(upc, true);
|
|
||||||
break;
|
|
||||||
case '\004':
|
|
||||||
passphrase_done(upc, false);
|
|
||||||
break;
|
|
||||||
case '\b':
|
|
||||||
case '\177':
|
|
||||||
strbuf_shrink_by(upc->debug_prompt_buf, 1);
|
|
||||||
break;
|
|
||||||
case '\025':
|
|
||||||
strbuf_clear(upc->debug_prompt_buf);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
put_byte(upc->debug_prompt_buf, c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When we come here, we're terminating, and should clean up our
|
* Before terminating, clean up our Unix socket file if possible.
|
||||||
* Unix socket file if possible.
|
|
||||||
*/
|
*/
|
||||||
if (unlink(socketname) < 0) {
|
if (unlink(socketname) < 0) {
|
||||||
fprintf(stderr, "pageant: %s: %s\n", socketname, strerror(errno));
|
fprintf(stderr, "pageant: %s: %s\n", socketname, strerror(errno));
|
||||||
@ -1132,8 +1054,6 @@ void run_agent(FILE *logfp, const char *symlink_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
conf_free(conf);
|
conf_free(conf);
|
||||||
pollwrap_free(pw);
|
|
||||||
sfree(fdlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
244
unix/uxplink.c
244
unix/uxplink.c
@ -484,13 +484,6 @@ void sigwinch(int signum)
|
|||||||
/* not much we can do about it */;
|
/* not much we can do about it */;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* In Plink our selects are synchronous, so these functions are
|
|
||||||
* empty stubs.
|
|
||||||
*/
|
|
||||||
uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; }
|
|
||||||
void uxsel_input_remove(uxsel_id *id) { }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Short description of parameters.
|
* Short description of parameters.
|
||||||
*/
|
*/
|
||||||
@ -575,24 +568,95 @@ const unsigned cmdline_tooltype =
|
|||||||
TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
|
TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
|
||||||
TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD;
|
TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD;
|
||||||
|
|
||||||
|
static bool sending;
|
||||||
|
|
||||||
|
static bool plink_pw_setup(void *vctx, pollwrapper *pw)
|
||||||
|
{
|
||||||
|
pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);
|
||||||
|
|
||||||
|
if (!sending &&
|
||||||
|
backend_connected(backend) &&
|
||||||
|
backend_sendok(backend) &&
|
||||||
|
backend_sendbuffer(backend) < MAX_STDIN_BACKLOG) {
|
||||||
|
/* If we're OK to send, then try to read from stdin. */
|
||||||
|
pollwrap_add_fd_rwx(pw, STDIN_FILENO, SELECT_R);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufchain_size(&stdout_data) > 0) {
|
||||||
|
/* If we have data for stdout, try to write to stdout. */
|
||||||
|
pollwrap_add_fd_rwx(pw, STDOUT_FILENO, SELECT_W);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufchain_size(&stderr_data) > 0) {
|
||||||
|
/* If we have data for stderr, try to write to stderr. */
|
||||||
|
pollwrap_add_fd_rwx(pw, STDERR_FILENO, SELECT_W);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void plink_pw_check(void *vctx, pollwrapper *pw)
|
||||||
|
{
|
||||||
|
if (pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
|
||||||
|
char c[1];
|
||||||
|
struct winsize size;
|
||||||
|
if (read(signalpipe[0], c, 1) <= 0)
|
||||||
|
/* ignore error */;
|
||||||
|
/* ignore its value; it'll be `x' */
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCGWINSZ, (void *)&size) >= 0)
|
||||||
|
backend_size(backend, size.ws_col, size.ws_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollwrap_check_fd_rwx(pw, STDIN_FILENO, SELECT_R)) {
|
||||||
|
char buf[4096];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (backend_connected(backend)) {
|
||||||
|
ret = read(STDIN_FILENO, buf, sizeof(buf));
|
||||||
|
noise_ultralight(NOISE_SOURCE_IOLEN, ret);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("stdin: read");
|
||||||
|
exit(1);
|
||||||
|
} else if (ret == 0) {
|
||||||
|
backend_special(backend, SS_EOF, 0);
|
||||||
|
sending = false; /* send nothing further after this */
|
||||||
|
} else {
|
||||||
|
if (local_tty)
|
||||||
|
from_tty(buf, ret);
|
||||||
|
else
|
||||||
|
backend_send(backend, buf, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollwrap_check_fd_rwx(pw, STDOUT_FILENO, SELECT_W)) {
|
||||||
|
backend_unthrottle(backend, try_output(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollwrap_check_fd_rwx(pw, STDERR_FILENO, SELECT_W)) {
|
||||||
|
backend_unthrottle(backend, try_output(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool plink_continue(void *vctx, bool found_any_fd,
|
||||||
|
bool ran_any_callback)
|
||||||
|
{
|
||||||
|
if (!backend_connected(backend) &&
|
||||||
|
bufchain_size(&stdout_data) == 0 && bufchain_size(&stderr_data) == 0)
|
||||||
|
return false; /* terminate main loop */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
bool sending;
|
|
||||||
int *fdlist;
|
|
||||||
int fd;
|
|
||||||
int i, fdstate;
|
|
||||||
size_t fdsize;
|
|
||||||
int exitcode;
|
int exitcode;
|
||||||
bool errors;
|
bool errors;
|
||||||
enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO;
|
enum TriState sanitise_stdout = AUTO, sanitise_stderr = AUTO;
|
||||||
bool use_subsystem = false;
|
bool use_subsystem = false;
|
||||||
bool just_test_share_exists = false;
|
bool just_test_share_exists = false;
|
||||||
unsigned long now;
|
|
||||||
struct winsize size;
|
struct winsize size;
|
||||||
const struct BackendVtable *backvt;
|
const struct BackendVtable *backvt;
|
||||||
|
|
||||||
fdlist = NULL;
|
|
||||||
fdsize = 0;
|
|
||||||
/*
|
/*
|
||||||
* Initialise port and protocol to sensible defaults. (These
|
* Initialise port and protocol to sensible defaults. (These
|
||||||
* will be overridden by more or less anything.)
|
* will be overridden by more or less anything.)
|
||||||
@ -875,157 +939,9 @@ int main(int argc, char **argv)
|
|||||||
atexit(cleanup_termios);
|
atexit(cleanup_termios);
|
||||||
seat_echoedit_update(plink_seat, 1, 1);
|
seat_echoedit_update(plink_seat, 1, 1);
|
||||||
sending = false;
|
sending = false;
|
||||||
now = GETTICKCOUNT();
|
|
||||||
|
|
||||||
pollwrapper *pw = pollwrap_new();
|
cli_main_loop(plink_pw_setup, plink_pw_check, plink_continue, NULL);
|
||||||
|
|
||||||
while (1) {
|
|
||||||
int rwx;
|
|
||||||
int ret;
|
|
||||||
unsigned long next;
|
|
||||||
|
|
||||||
pollwrap_clear(pw);
|
|
||||||
|
|
||||||
pollwrap_add_fd_rwx(pw, signalpipe[0], SELECT_R);
|
|
||||||
|
|
||||||
if (!sending &&
|
|
||||||
backend_connected(backend) &&
|
|
||||||
backend_sendok(backend) &&
|
|
||||||
backend_sendbuffer(backend) < MAX_STDIN_BACKLOG) {
|
|
||||||
/* If we're OK to send, then try to read from stdin. */
|
|
||||||
pollwrap_add_fd_rwx(pw, STDIN_FILENO, SELECT_R);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufchain_size(&stdout_data) > 0) {
|
|
||||||
/* If we have data for stdout, try to write to stdout. */
|
|
||||||
pollwrap_add_fd_rwx(pw, STDOUT_FILENO, SELECT_W);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufchain_size(&stderr_data) > 0) {
|
|
||||||
/* If we have data for stderr, try to write to stderr. */
|
|
||||||
pollwrap_add_fd_rwx(pw, STDERR_FILENO, SELECT_W);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Count the currently active fds. */
|
|
||||||
i = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) i++;
|
|
||||||
|
|
||||||
/* Expand the fdlist buffer if necessary. */
|
|
||||||
sgrowarray(fdlist, fdsize, i);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add all currently open fds to pw, and store them in fdlist
|
|
||||||
* as well.
|
|
||||||
*/
|
|
||||||
int fdcount = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) {
|
|
||||||
fdlist[fdcount++] = fd;
|
|
||||||
pollwrap_add_fd_rwx(pw, fd, rwx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toplevel_callback_pending()) {
|
|
||||||
ret = pollwrap_poll_instant(pw);
|
|
||||||
} else if (run_timers(now, &next)) {
|
|
||||||
do {
|
|
||||||
unsigned long then;
|
|
||||||
long ticks;
|
|
||||||
|
|
||||||
then = now;
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
if (now - then > next - then)
|
|
||||||
ticks = 0;
|
|
||||||
else
|
|
||||||
ticks = next - now;
|
|
||||||
|
|
||||||
bool overflow = false;
|
|
||||||
if (ticks > INT_MAX) {
|
|
||||||
ticks = INT_MAX;
|
|
||||||
overflow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = pollwrap_poll_timeout(pw, ticks);
|
|
||||||
if (ret == 0 && !overflow)
|
|
||||||
now = next;
|
|
||||||
else
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
} else {
|
|
||||||
ret = pollwrap_poll_endless(pw);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0 && errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("poll");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < fdcount; i++) {
|
|
||||||
fd = fdlist[i];
|
|
||||||
int rwx = pollwrap_get_fd_rwx(pw, fd);
|
|
||||||
/*
|
|
||||||
* We must process exceptional notifications before
|
|
||||||
* ordinary readability ones, or we may go straight
|
|
||||||
* past the urgent marker.
|
|
||||||
*/
|
|
||||||
if (rwx & SELECT_X)
|
|
||||||
select_result(fd, SELECT_X);
|
|
||||||
if (rwx & SELECT_R)
|
|
||||||
select_result(fd, SELECT_R);
|
|
||||||
if (rwx & SELECT_W)
|
|
||||||
select_result(fd, SELECT_W);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollwrap_check_fd_rwx(pw, signalpipe[0], SELECT_R)) {
|
|
||||||
char c[1];
|
|
||||||
struct winsize size;
|
|
||||||
if (read(signalpipe[0], c, 1) <= 0)
|
|
||||||
/* ignore error */;
|
|
||||||
/* ignore its value; it'll be `x' */
|
|
||||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, (void *)&size) >= 0)
|
|
||||||
backend_size(backend, size.ws_col, size.ws_row);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollwrap_check_fd_rwx(pw, STDIN_FILENO, SELECT_R)) {
|
|
||||||
char buf[4096];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (backend_connected(backend)) {
|
|
||||||
ret = read(STDIN_FILENO, buf, sizeof(buf));
|
|
||||||
noise_ultralight(NOISE_SOURCE_IOLEN, ret);
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("stdin: read");
|
|
||||||
exit(1);
|
|
||||||
} else if (ret == 0) {
|
|
||||||
backend_special(backend, SS_EOF, 0);
|
|
||||||
sending = false; /* send nothing further after this */
|
|
||||||
} else {
|
|
||||||
if (local_tty)
|
|
||||||
from_tty(buf, ret);
|
|
||||||
else
|
|
||||||
backend_send(backend, buf, ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollwrap_check_fd_rwx(pw, STDOUT_FILENO, SELECT_W)) {
|
|
||||||
backend_unthrottle(backend, try_output(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollwrap_check_fd_rwx(pw, STDERR_FILENO, SELECT_W)) {
|
|
||||||
backend_unthrottle(backend, try_output(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
|
||||||
|
|
||||||
if (!backend_connected(backend) &&
|
|
||||||
bufchain_size(&stdout_data) == 0 &&
|
|
||||||
bufchain_size(&stderr_data) == 0)
|
|
||||||
break; /* we closed the connection */
|
|
||||||
}
|
|
||||||
exitcode = backend_exitcode(backend);
|
exitcode = backend_exitcode(backend);
|
||||||
if (exitcode < 0) {
|
if (exitcode < 0) {
|
||||||
fprintf(stderr, "Remote process exit code unavailable\n");
|
fprintf(stderr, "Remote process exit code unavailable\n");
|
||||||
|
104
unix/uxserver.c
104
unix/uxserver.c
@ -95,12 +95,6 @@ char *x_get_default(const char *key)
|
|||||||
return NULL; /* this is a stub */
|
return NULL; /* this is a stub */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Our selects are synchronous, so these functions are empty stubs.
|
|
||||||
*/
|
|
||||||
uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; }
|
|
||||||
void uxsel_input_remove(uxsel_id *id) { }
|
|
||||||
|
|
||||||
void old_keyfile_warning(void) { }
|
void old_keyfile_warning(void) { }
|
||||||
|
|
||||||
void timer_change_notify(unsigned long next)
|
void timer_change_notify(unsigned long next)
|
||||||
@ -519,11 +513,6 @@ static const PlugVtable server_plugvt = {
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int *fdlist;
|
|
||||||
int fd;
|
|
||||||
int i, fdstate;
|
|
||||||
size_t fdsize;
|
|
||||||
unsigned long now;
|
|
||||||
int listen_port = -1;
|
int listen_port = -1;
|
||||||
|
|
||||||
ssh_key **hostkeys = NULL;
|
ssh_key **hostkeys = NULL;
|
||||||
@ -598,7 +587,7 @@ int main(int argc, char **argv)
|
|||||||
sfree(uk->comment);
|
sfree(uk->comment);
|
||||||
sfree(uk);
|
sfree(uk);
|
||||||
|
|
||||||
for (i = 0; i < nhostkeys; i++)
|
for (int i = 0; i < nhostkeys; i++)
|
||||||
if (ssh_key_alg(hostkeys[i]) == ssh_key_alg(key)) {
|
if (ssh_key_alg(hostkeys[i]) == ssh_key_alg(key)) {
|
||||||
fprintf(stderr, "%s: host key '%s' duplicates key "
|
fprintf(stderr, "%s: host key '%s' duplicates key "
|
||||||
"type %s\n", appname, val,
|
"type %s\n", appname, val,
|
||||||
@ -792,9 +781,6 @@ int main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fdlist = NULL;
|
|
||||||
fdsize = 0;
|
|
||||||
|
|
||||||
random_ref();
|
random_ref();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -832,90 +818,8 @@ int main(int argc, char **argv)
|
|||||||
log_to_stderr(inst->id, "speaking SSH on stdio");
|
log_to_stderr(inst->id, "speaking SSH on stdio");
|
||||||
}
|
}
|
||||||
|
|
||||||
now = GETTICKCOUNT();
|
cli_main_loop(cliloop_no_pw_setup, cliloop_no_pw_check,
|
||||||
|
cliloop_always_continue, NULL);
|
||||||
|
|
||||||
pollwrapper *pw = pollwrap_new();
|
return 0;
|
||||||
while (!finished) {
|
|
||||||
int rwx;
|
|
||||||
int ret;
|
|
||||||
unsigned long next;
|
|
||||||
|
|
||||||
pollwrap_clear(pw);
|
|
||||||
|
|
||||||
/* Count the currently active fds. */
|
|
||||||
i = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) i++;
|
|
||||||
|
|
||||||
/* Expand the fdlist buffer if necessary. */
|
|
||||||
sgrowarray(fdlist, fdsize, i);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add all currently open fds to the select sets, and store
|
|
||||||
* them in fdlist as well.
|
|
||||||
*/
|
|
||||||
int fdcount = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) {
|
|
||||||
fdlist[fdcount++] = fd;
|
|
||||||
pollwrap_add_fd_rwx(pw, fd, rwx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toplevel_callback_pending()) {
|
|
||||||
ret = pollwrap_poll_instant(pw);
|
|
||||||
} else if (run_timers(now, &next)) {
|
|
||||||
do {
|
|
||||||
unsigned long then;
|
|
||||||
long ticks;
|
|
||||||
|
|
||||||
then = now;
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
if (now - then > next - then)
|
|
||||||
ticks = 0;
|
|
||||||
else
|
|
||||||
ticks = next - now;
|
|
||||||
|
|
||||||
bool overflow = false;
|
|
||||||
if (ticks > INT_MAX) {
|
|
||||||
ticks = INT_MAX;
|
|
||||||
overflow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = pollwrap_poll_timeout(pw, ticks);
|
|
||||||
if (ret == 0 && !overflow)
|
|
||||||
now = next;
|
|
||||||
else
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
} else {
|
|
||||||
ret = pollwrap_poll_endless(pw);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0 && errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("poll");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < fdcount; i++) {
|
|
||||||
fd = fdlist[i];
|
|
||||||
int rwx = pollwrap_get_fd_rwx(pw, fd);
|
|
||||||
/*
|
|
||||||
* We must process exceptional notifications before
|
|
||||||
* ordinary readability ones, or we may go straight
|
|
||||||
* past the urgent marker.
|
|
||||||
*/
|
|
||||||
if (rwx & SELECT_X)
|
|
||||||
select_result(fd, SELECT_X);
|
|
||||||
if (rwx & SELECT_R)
|
|
||||||
select_result(fd, SELECT_R);
|
|
||||||
if (rwx & SELECT_W)
|
|
||||||
select_result(fd, SELECT_W);
|
|
||||||
}
|
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
156
unix/uxsftp.c
156
unix/uxsftp.c
@ -21,13 +21,6 @@
|
|||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* In PSFTP our selects are synchronous, so these functions are
|
|
||||||
* empty stubs.
|
|
||||||
*/
|
|
||||||
uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; }
|
|
||||||
void uxsel_input_remove(uxsel_id *id) { }
|
|
||||||
|
|
||||||
char *x_get_default(const char *key)
|
char *x_get_default(const char *key)
|
||||||
{
|
{
|
||||||
return NULL; /* this is a stub */
|
return NULL; /* this is a stub */
|
||||||
@ -465,116 +458,55 @@ char *dir_file_cat(const char *dir, const char *file)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a select() between all currently active network fds and
|
* Do a select() between all currently active network fds and
|
||||||
* optionally stdin.
|
* optionally stdin, using cli_main_loop.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct ssh_sftp_mainloop_ctx {
|
||||||
|
bool include_stdin, no_fds_ok;
|
||||||
|
int toret;
|
||||||
|
};
|
||||||
|
static bool ssh_sftp_pw_setup(void *vctx, pollwrapper *pw)
|
||||||
|
{
|
||||||
|
struct ssh_sftp_mainloop_ctx *ctx = (struct ssh_sftp_mainloop_ctx *)vctx;
|
||||||
|
int fdstate, rwx;
|
||||||
|
|
||||||
|
if (!ctx->no_fds_ok && !toplevel_callback_pending() &&
|
||||||
|
first_fd(&fdstate, &rwx) < 0) {
|
||||||
|
ctx->toret = -1;
|
||||||
|
return false; /* terminate cli_main_loop */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->include_stdin)
|
||||||
|
pollwrap_add_fd_rwx(pw, 0, SELECT_R);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static void ssh_sftp_pw_check(void *vctx, pollwrapper *pw)
|
||||||
|
{
|
||||||
|
struct ssh_sftp_mainloop_ctx *ctx = (struct ssh_sftp_mainloop_ctx *)vctx;
|
||||||
|
|
||||||
|
if (ctx->include_stdin && pollwrap_check_fd_rwx(pw, 0, SELECT_R))
|
||||||
|
ctx->toret = 1;
|
||||||
|
}
|
||||||
|
static bool ssh_sftp_mainloop_continue(void *vctx, bool found_any_fd,
|
||||||
|
bool ran_any_callback)
|
||||||
|
{
|
||||||
|
struct ssh_sftp_mainloop_ctx *ctx = (struct ssh_sftp_mainloop_ctx *)vctx;
|
||||||
|
if (ctx->toret != 0 || found_any_fd || ran_any_callback)
|
||||||
|
return false; /* finish the loop */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
|
static int ssh_sftp_do_select(bool include_stdin, bool no_fds_ok)
|
||||||
{
|
{
|
||||||
int i, *fdlist;
|
struct ssh_sftp_mainloop_ctx ctx[1];
|
||||||
size_t fdsize;
|
ctx->include_stdin = include_stdin;
|
||||||
int fd, fdcount, fdstate, rwx, ret;
|
ctx->no_fds_ok = no_fds_ok;
|
||||||
unsigned long now = GETTICKCOUNT();
|
ctx->toret = 0;
|
||||||
unsigned long next;
|
|
||||||
bool done_something = false;
|
|
||||||
|
|
||||||
fdlist = NULL;
|
cli_main_loop(ssh_sftp_pw_setup, ssh_sftp_pw_check,
|
||||||
fdsize = 0;
|
ssh_sftp_mainloop_continue, ctx);
|
||||||
|
|
||||||
pollwrapper *pw = pollwrap_new();
|
return ctx->toret;
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
/* Count the currently active fds. */
|
|
||||||
i = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) i++;
|
|
||||||
|
|
||||||
if (i < 1 && !no_fds_ok && !toplevel_callback_pending()) {
|
|
||||||
pollwrap_free(pw);
|
|
||||||
return -1; /* doom */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expand the fdlist buffer if necessary. */
|
|
||||||
sgrowarray(fdlist, fdsize, i);
|
|
||||||
|
|
||||||
pollwrap_clear(pw);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add all currently open fds to the select sets, and store
|
|
||||||
* them in fdlist as well.
|
|
||||||
*/
|
|
||||||
fdcount = 0;
|
|
||||||
for (fd = first_fd(&fdstate, &rwx); fd >= 0;
|
|
||||||
fd = next_fd(&fdstate, &rwx)) {
|
|
||||||
fdlist[fdcount++] = fd;
|
|
||||||
pollwrap_add_fd_rwx(pw, fd, rwx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (include_stdin)
|
|
||||||
pollwrap_add_fd_rwx(pw, 0, SELECT_R);
|
|
||||||
|
|
||||||
if (toplevel_callback_pending()) {
|
|
||||||
ret = pollwrap_poll_instant(pw);
|
|
||||||
if (ret == 0)
|
|
||||||
done_something |= run_toplevel_callbacks();
|
|
||||||
} else if (run_timers(now, &next)) {
|
|
||||||
do {
|
|
||||||
unsigned long then;
|
|
||||||
long ticks;
|
|
||||||
|
|
||||||
then = now;
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
if (now - then > next - then)
|
|
||||||
ticks = 0;
|
|
||||||
else
|
|
||||||
ticks = next - now;
|
|
||||||
|
|
||||||
bool overflow = false;
|
|
||||||
if (ticks > INT_MAX) {
|
|
||||||
ticks = INT_MAX;
|
|
||||||
overflow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = pollwrap_poll_timeout(pw, ticks);
|
|
||||||
if (ret == 0 && !overflow)
|
|
||||||
now = next;
|
|
||||||
else
|
|
||||||
now = GETTICKCOUNT();
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
ret = pollwrap_poll_endless(pw);
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
}
|
|
||||||
} while (ret == 0 && !done_something);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("poll");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < fdcount; i++) {
|
|
||||||
fd = fdlist[i];
|
|
||||||
int rwx = pollwrap_get_fd_rwx(pw, fd);
|
|
||||||
/*
|
|
||||||
* We must process exceptional notifications before
|
|
||||||
* ordinary readability ones, or we may go straight
|
|
||||||
* past the urgent marker.
|
|
||||||
*/
|
|
||||||
if (rwx & SELECT_X)
|
|
||||||
select_result(fd, SELECT_X);
|
|
||||||
if (rwx & SELECT_R)
|
|
||||||
select_result(fd, SELECT_R);
|
|
||||||
if (rwx & SELECT_W)
|
|
||||||
select_result(fd, SELECT_W);
|
|
||||||
}
|
|
||||||
|
|
||||||
sfree(fdlist);
|
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
|
||||||
|
|
||||||
int toret = pollwrap_check_fd_rwx(pw, 0, SELECT_R) ? 1 : 0;
|
|
||||||
pollwrap_free(pw);
|
|
||||||
return toret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user