X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/56e5b2db28757ed9b09f15c66e5b13eae241d4e6..c7edb1cca5c2b3f3642034104dcf49656cd8678e:/unix/uxplink.c diff --git a/unix/uxplink.c b/unix/uxplink.c index dab69475..451d1121 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -4,11 +4,15 @@ #include #include +#include #include #include +#include #include #include #include +#include +#include /* More helpful version of the FD_SET macro, to also handle maxfd. */ #define FD_SET_MAX(fd, max, set) do { \ @@ -68,8 +72,88 @@ struct termios orig_termios; static Backend *back; static void *backhandle; +static Config cfg; -char *x_get_default(char *key) +/* + * Default settings that are specific to pterm. + */ +char *platform_default_s(const char *name) +{ + if (!strcmp(name, "X11Display")) + return getenv("DISPLAY"); + if (!strcmp(name, "TermType")) + return getenv("TERM"); + if (!strcmp(name, "UserName")) { + /* + * Remote login username will default to the local username. + */ + struct passwd *p; + uid_t uid = getuid(); + char *user, *ret = NULL; + + /* + * First, find who we think we are using getlogin. If this + * agrees with our uid, we'll go along with it. This should + * allow sharing of uids between several login names whilst + * coping correctly with people who have su'ed. + */ + user = getlogin(); + setpwent(); + if (user) + p = getpwnam(user); + else + p = NULL; + if (p && p->pw_uid == uid) { + /* + * The result of getlogin() really does correspond to + * our uid. Fine. + */ + ret = user; + } else { + /* + * If that didn't work, for whatever reason, we'll do + * the simpler version: look up our uid in the password + * file and map it straight to a name. + */ + p = getpwuid(uid); + ret = p->pw_name; + } + endpwent(); + + return ret; + } + return NULL; +} + +int platform_default_i(const char *name, int def) +{ + if (!strcmp(name, "TermWidth") || + !strcmp(name, "TermHeight")) { + struct winsize size; + if (ioctl(0, TIOCGWINSZ, (void *)&size) >= 0) + return (!strcmp(name, "TermWidth") ? size.ws_col : size.ws_row); + } + return def; +} + +FontSpec platform_default_fontspec(const char *name) +{ + FontSpec ret; + *ret.name = '\0'; + return ret; +} + +Filename platform_default_filename(const char *name) +{ + Filename ret; + if (!strcmp(name, "LogFileName")) + strcpy(ret.path, "putty.log"); + else + *ret.path = '\0'; + return ret; +} + +char *x_get_default(const char *key) { return NULL; /* this is a stub */ } @@ -111,6 +195,9 @@ void try_output(int is_stderr) void *senddata; int sendlen, ret; + if (bufchain_size(chain) == 0) + return; + bufchain_prefix(chain, &senddata, &sendlen); ret = write(fd, senddata, sendlen); if (ret > 0) @@ -121,7 +208,8 @@ void try_output(int is_stderr) } } -int from_backend(void *frontend_handle, int is_stderr, char *data, int len) +int from_backend(void *frontend_handle, int is_stderr, + const char *data, int len) { int osize, esize; @@ -141,6 +229,20 @@ int from_backend(void *frontend_handle, int is_stderr, char *data, int len) return osize + esize; } +int signalpipe[2]; + +void sigwinch(int signum) +{ + write(signalpipe[1], "x", 1); +} + +/* + * In Plink our selects are synchronous, so these functions are + * empty stubs. + */ +int uxsel_input_add(int fd, int rwx) { return 0; } +void uxsel_input_remove(int id) { } + /* * Short description of parameters. */ @@ -178,18 +280,18 @@ int main(int argc, char **argv) { int sending; int portnumber = -1; - int *sklist; - int socket; - int i, skcount, sksize, socketstate; + int *fdlist; + int fd; + int i, fdcount, fdsize, fdstate; int connopen; int exitcode; - void *logctx; + int errors; void *ldisc; ssh_get_line = console_get_line; - sklist = NULL; - skcount = sksize = 0; + fdlist = NULL; + fdcount = fdsize = 0; /* * Initialise port and protocol to sensible defaults. (These * will be overridden by more or less anything.) @@ -204,6 +306,7 @@ int main(int argc, char **argv) do_defaults(NULL, &cfg); default_protocol = cfg.protocol; default_port = cfg.port; + errors = 0; { /* * Override the default protocol if PLINK_PROTOCOL is set. @@ -224,20 +327,37 @@ int main(int argc, char **argv) while (--argc) { char *p = *++argv; if (*p == '-') { - int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), 1); + int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), + 1, &cfg); if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); + errors = 1; } else if (ret == 2) { --argc, ++argv; } else if (ret == 1) { continue; } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; + } else if (!strcmp(p, "-o")) { + if (argc <= 1) { + fprintf(stderr, + "plink: option \"-o\" requires an argument\n"); + errors = 1; + } else { + --argc; + provide_xrm_string(*++argv); + } + } else { + fprintf(stderr, "plink: unknown option \"%s\"\n", p); + errors = 1; } } else if (*p) { if (!*cfg.host) { char *q = p; + + do_defaults(NULL, &cfg); + /* * If the hostname starts with "telnet:", set the * protocol to Telnet and process the string as a @@ -333,13 +453,13 @@ int main(int argc, char **argv) while (*p) { if (cmdlen >= cmdsize) { cmdsize = cmdlen + 512; - command = srealloc(command, cmdsize); + command = sresize(command, cmdsize, char); } command[cmdlen++]=*p++; } if (cmdlen >= cmdsize) { cmdsize = cmdlen + 512; - command = srealloc(command, cmdsize); + command = sresize(command, cmdsize, char); } command[cmdlen++]=' '; /* always add trailing space */ if (--argc) p = *++argv; @@ -355,6 +475,9 @@ int main(int argc, char **argv) } } + if (errors) + return 1; + if (!*cfg.host) { usage(); } @@ -383,7 +506,7 @@ int main(int argc, char **argv) /* * Perform command-line overrides on session configuration. */ - cmdline_run_saved(); + cmdline_run_saved(&cfg); /* * Trim a colon suffix off the hostname if it's there. @@ -433,26 +556,36 @@ int main(int argc, char **argv) if (portnumber != -1) cfg.port = portnumber; + /* + * Set up the pipe we'll use to tell us about SIGWINCH. + */ + if (pipe(signalpipe) < 0) { + perror("pipe"); + exit(1); + } + putty_signal(SIGWINCH, sigwinch); + sk_init(); + uxsel_init(); /* * Start up the connection. */ + logctx = log_init(NULL, &cfg); { char *error; char *realhost; /* nodelay is only useful if stdin is a terminal device */ int nodelay = cfg.tcp_nodelay && isatty(0); - error = back->init(NULL, &backhandle, cfg.host, cfg.port, + error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, nodelay); if (error) { fprintf(stderr, "Unable to open connection:\n%s\n", error); return 1; } - logctx = log_init(NULL); back->provide_logctx(backhandle, logctx); - ldisc = ldisc_create(NULL, back, backhandle, NULL); + ldisc = ldisc_create(&cfg, NULL, back, backhandle, NULL); sfree(realhost); } connopen = 1; @@ -478,6 +611,8 @@ int main(int argc, char **argv) FD_ZERO(&xset); maxfd = 0; + FD_SET_MAX(signalpipe[0], maxfd, rset); + if (connopen && !sending && back->socket(backhandle) != NULL && back->sendok(backhandle) && @@ -496,53 +631,63 @@ int main(int argc, char **argv) FD_SET_MAX(2, maxfd, wset); } - /* Count the currently active sockets. */ + /* Count the currently active fds. */ i = 0; - for (socket = first_socket(&socketstate, &rwx); socket >= 0; - socket = next_socket(&socketstate, &rwx)) i++; + for (fd = first_fd(&fdstate, &rwx); fd >= 0; + fd = next_fd(&fdstate, &rwx)) i++; - /* Expand the sklist buffer if necessary. */ - if (i > sksize) { - sksize = i + 16; - sklist = srealloc(sklist, sksize * sizeof(*sklist)); + /* Expand the fdlist buffer if necessary. */ + if (i > fdsize) { + fdsize = i + 16; + fdlist = sresize(fdlist, fdsize, int); } /* - * Add all currently open sockets to the select sets, and - * store them in sklist as well. + * Add all currently open fds to the select sets, and store + * them in fdlist as well. */ - skcount = 0; - for (socket = first_socket(&socketstate, &rwx); socket >= 0; - socket = next_socket(&socketstate, &rwx)) { - sklist[skcount++] = socket; + fdcount = 0; + for (fd = first_fd(&fdstate, &rwx); fd >= 0; + fd = next_fd(&fdstate, &rwx)) { + fdlist[fdcount++] = fd; if (rwx & 1) - FD_SET_MAX(socket, maxfd, rset); + FD_SET_MAX(fd, maxfd, rset); if (rwx & 2) - FD_SET_MAX(socket, maxfd, wset); + FD_SET_MAX(fd, maxfd, wset); if (rwx & 4) - FD_SET_MAX(socket, maxfd, xset); + FD_SET_MAX(fd, maxfd, xset); } - ret = select(maxfd, &rset, &wset, &xset, NULL); + do { + ret = select(maxfd, &rset, &wset, &xset, NULL); + } while (ret < 0 && errno == EINTR); if (ret < 0) { perror("select"); exit(1); } - for (i = 0; i < skcount; i++) { - socket = sklist[i]; + for (i = 0; i < fdcount; i++) { + fd = fdlist[i]; /* * We must process exceptional notifications before * ordinary readability ones, or we may go straight * past the urgent marker. */ - if (FD_ISSET(socket, &xset)) - select_result(socket, 4); - if (FD_ISSET(socket, &rset)) - select_result(socket, 1); - if (FD_ISSET(socket, &wset)) - select_result(socket, 2); + if (FD_ISSET(fd, &xset)) + select_result(fd, 4); + if (FD_ISSET(fd, &rset)) + select_result(fd, 1); + if (FD_ISSET(fd, &wset)) + select_result(fd, 2); + } + + if (FD_ISSET(signalpipe[0], &rset)) { + char c[1]; + struct winsize size; + read(signalpipe[0], c, 1); /* ignore its value; it'll be `x' */ + if (ioctl(0, TIOCGWINSZ, (void *)&size) >= 0) + back->size(backhandle, size.ws_col, size.ws_row); } if (FD_ISSET(0, &rset)) { @@ -581,5 +726,6 @@ int main(int argc, char **argv) fprintf(stderr, "Remote process exit code unavailable\n"); exitcode = 1; /* this is an error condition */ } - return exitcode; + cleanup_exit(exitcode); + return exitcode; /* shouldn't happen, but placates gcc */ }