Rewrite much of client's playing phase code:

(EOF_COOKIE, INTR_COOKIE, input_fd, send_intr, recv_output)
(recv_input, intr, play): New playing phase code.  No native Windows
support yet.  Sends just one EOF cookie on EOF on standard input
instead of up to three.  Old servers (before recvclient.c rev. 1.16)
fail to terminate the session when they receive an EOF cookie at an
argument prompt.  The session then hangs; use SIGINT to get out.  No
longer blocks on sending input, which could deadlock the session.
Closes #827090.  Fixes error handling for select().  Fixes race
condition that could cause server output to be discarded on EOF on
standard input.
(main): Replace old playing phase code by a call to play().
(intr, sock, interrupt, handleintr): Replaced by play(), remove.
[_WIN32] (hStdIn): Ditto.
(auxfp): New.
(servercmd, prompt, doexecute): Remove parameter auxfi, use auxfp.
(eight_bit_clean): Move to servcmd.c.
(servercmd): Work on a single non-C_DATA line instead of getting lines
from an ioqueue.
(servercmd, output, screen, outch): Deal with all ids in servercmd()
rather than some there and some in output().  Don't treat C_NOECHO,
C_ABORT, C_CMDERR, C_BADCMD specially.  Fix C_FLASH and C_EXIT to
ignore redirections; they used to ignore them only for some parts.
Replace output() by outch(), fold screen into outch().
(servercmd): Truncate long prompts and telegram infos to prevent
buffer overflow.
(prompt): Use new parameters code, prompt, teles instead of global
variables mode, the_prompt, num_teles.
(num_teles, the_prompt, mode, nbtu, nmin): Remove.
(prompt): Don't write an empty line before argument prompts to auxfp.
(servercmd): Don't strip newline from redirections and execute,
doredir(), dopipe() and doexecute() need it now.
(doredir, dopipe, doexecute): Use new seen_input() instead of gettag().
(doexecute): Set input_fd and leave reading the script file to play().
(serverio, termio, sendeof): Replaced by play(), remove.
(LBUF_LEN_MAX, lbuf, lbuf_init, lbuf_len, lbuf_full, lbuf_line)
(lbuf_putc): New.
(RING_SIZE, ring, ring_init, ring_len, ring_space, ring_peek)
(ring_getc, ring_putc, ring_putm, ring_discard, ring_search)
(ring_from_file, ring_to_file): New.
(clear_recent_input, save_input, seen_input): New.
(MAX): New.
(ioqueue, io, ioq_init, ioq_dequeue, ioq_read, ioq_write, ioq_qsize)
(ioq_drain, ioq_gets, ioqtobuf, enqueuecc, dequeuecc): Unused, remove.
(QEMPTY, qelem, insque, remque, initque): Unused, remove.
(tagstruct, taglist, io_init, gettag): Unused, remove.
This commit is contained in:
Markus Armbruster 2007-11-17 14:17:38 +00:00
parent 2444a5c63a
commit 8b7d0b915d
15 changed files with 862 additions and 1127 deletions

View file

@ -35,119 +35,88 @@
#include <config.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include "ioqueue.h"
#include "misc.h"
#include "proto.h"
#include "tags.h"
#include "secure.h"
int eight_bit_clean;
FILE *auxfp;
static char num_teles[64];
static char the_prompt[1024];
static int mode;
static int nbtu;
static int nmin;
static FILE *redir_fp;
static FILE *pipe_fp;
static void prompt(FILE *auxfi);
static void prompt(int, char *, char *);
static void doredir(char *p);
static void dopipe(char *p);
static void doexecute(char *p, FILE *auxfi);
static void output(int code, char *buf, FILE *auxfi);
static void screen(char *buf);
static void doexecute(char *p);
void
servercmd(struct ioqueue *ioq, FILE *auxfi)
servercmd(int code, char *arg, int len)
{
char buf[1024];
char *p;
static int code = -1;
int eol;
static int nmin, nbtu;
static char the_prompt[1024];
static char teles[64];
while (ioq_gets(ioq, buf, sizeof(buf), &eol)) {
p = buf;
if (code == -1) {
if (isalpha(*buf))
code = 10 + (*buf - 'a');
else
code = *buf - '0';
while (*p && !isspace(*p))
p++;
*p++ = 0;
switch (code) {
case C_PROMPT:
if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
fprintf(stderr, "prompt: bad server prompt %s\n", arg);
}
/*
* FIXME
* C_REDIR, C_PIPE, and C_EXECUTE will not
* work with filename longer than one buffer
*/
switch (code) {
case C_PROMPT:
if (sscanf(p, "%d %d", &nmin, &nbtu) != 2) {
fprintf(stderr, "prompt: bad server prompt %s\n", p);
snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
nmin, nbtu);
prompt(code, the_prompt, teles);
break;
case C_FLUSH:
snprintf(the_prompt, sizeof(the_prompt), "%.*s", len - 1, arg);
prompt(code, the_prompt, teles);
break;
case C_EXECUTE:
doexecute(arg);
break;
case C_EXIT:
printf("Exit: %s", arg);
if (auxfp)
fprintf(auxfp, "Exit: %s", arg);
break;
case C_FLASH:
printf("\n%s", arg);
if (auxfp)
fprintf(auxfp, "\n%s", arg);
break;
case C_INFORM:
if (*arg) {
snprintf(teles, sizeof(teles), "(%.*s )", len -1, arg);
if (!redir_fp && !pipe_fp) {
putchar('\07');
prompt(code, the_prompt, teles);
}
mode = code;
sprintf(the_prompt, "[%d:%d] Command : ", nmin, nbtu);
prompt(auxfi);
break;
case C_REDIR:
if (eol)
p[strlen(p) - 1] = '\0';
doredir(p);
break;
case C_PIPE:
if (eol)
p[strlen(p) - 1] = '\0';
dopipe(p);
break;
case C_FLUSH:
mode = code;
if (eol)
p[strlen(p) - 1] = '\0';
sprintf(the_prompt, "%s", p);
prompt(auxfi);
break;
case C_EXECUTE:
if (eol)
p[strlen(p) - 1] = '\0';
doexecute(p, auxfi);
break;
case C_INFORM:
if (eol)
p[strlen(p) - 1] = '\0';
if (*p) {
p[strlen(p) - 1] = '\0';
sprintf(num_teles, "(%s) ", p + 1);
if (!redir_fp && !pipe_fp) {
putchar('\07');
prompt(NULL);
}
} else
*num_teles = '\0';
break;
default:
output(code, p, auxfi);
break;
}
if (eol)
code = -1;
} else
teles[0] = 0;
break;
case C_PIPE:
dopipe(arg);
break;
case C_REDIR:
doredir(arg);
break;
default:
assert(0);
break;
}
}
static void
prompt(FILE *auxfi)
prompt(int code, char *prompt, char *teles)
{
if (mode == C_PROMPT) {
char *nl;
if (code == C_PROMPT) {
if (redir_fp) {
(void)fclose(redir_fp);
redir_fp = NULL;
@ -156,13 +125,12 @@ prompt(FILE *auxfi)
pipe_fp = NULL;
}
}
if (mode == C_PROMPT)
printf("\n");
printf("%s%s", num_teles, the_prompt);
(void)fflush(stdout);
if (auxfi) {
fprintf(auxfi, "\n%s%s", num_teles, the_prompt);
(void)fflush(auxfi);
nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
printf("%s%s%s", nl, teles, prompt);
fflush(stdout);
if (auxfp) {
fprintf(auxfp, "%s%s%s", nl, teles, prompt);
fflush(auxfp);
}
}
@ -183,7 +151,6 @@ fname(char *s)
static void
doredir(char *p)
{
char *tag;
int mode;
int fd;
@ -192,6 +159,12 @@ doredir(char *p)
redir_fp = NULL;
}
if (!seen_input(p)) {
fprintf(stderr, "WARNING! Server attempted to redirect %s\n",
p);
return;
}
if (*p++ != '>') {
fprintf(stderr, "WARNING! Weird redirection %s", p);
return;
@ -207,19 +180,12 @@ doredir(char *p)
} else
mode |= O_EXCL;
tag = gettag(p);
p = fname(p);
if (tag == NULL) {
fprintf(stderr, "WARNING! Server redirected output to file %s\n",
p);
return;
}
free(tag);
if (*p == 0) {
fprintf(stderr, "Redirection lacks a file name\n");
return;
}
fd = open(p, mode, 0600);
redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
if (!redir_fp) {
@ -234,25 +200,22 @@ doredir(char *p)
static void
dopipe(char *p)
{
char *tag;
if (!seen_input(p)) {
fprintf(stderr, "WARNING! Server attempted to pipe %s", p);
return;
}
if (*p++ != '|') {
fprintf(stderr, "WARNING! Weird pipe %s", p);
return;
}
tag = gettag(p);
if (tag == NULL) {
fprintf(stderr, "WARNING! Server attempted to run: %s\n", p);
return;
}
free(tag);
for (; *p && isspace(*p); p++) ;
if (*p == 0) {
fprintf(stderr, "Redirection lacks a command\n");
return;
}
if ((pipe_fp = popen(p, "w")) == NULL) {
fprintf(stderr, "Can't redirect to pipe %s: %s\n",
p, strerror(errno));
@ -260,103 +223,48 @@ dopipe(char *p)
}
static void
doexecute(char *p, FILE *auxfi)
doexecute(char *p)
{
int fd;
char *tag;
tag = gettag(p);
if (tag == NULL) {
if (!seen_input(p)) {
fprintf(stderr,
"WARNING! Server attempted unauthorized read of file %s\n",
"WARNING! Server attempted to read file %s",
p);
return;
}
free(tag);
p = fname(p);
if (*p == 0) {
fprintf(stderr, "Need a file to execute\n");
return;
}
if ((fd = open(p, O_RDONLY, 0)) < 0) {
if ((input_fd = open(p, O_RDONLY)) < 0) {
fprintf(stderr, "Can't open execute file %s: %s\n",
p, strerror(errno));
return;
}
/* copies 4k at a time to the socket */
while (termio(fd, sock, auxfi)) /*do copy */
;
/*
* Some platforms don't send the eof (cntl-D) at the end of
* copying a file. If emp_client hangs at the end of an
* execute, include the following line and notify wolfpack
* of the platform you are using.
* sendeof(sock);
*/
close(fd);
}
static void
output(int code, char *buf, FILE *auxfi)
void
outch(char c)
{
switch (code) {
case C_NOECHO:
/* not implemented; server doesn't send it */
break;
case C_ABORT:
printf("Aborted\n");
if (auxfi)
fprintf(auxfi, "Aborted\n");
break;
case C_CMDERR:
case C_BADCMD:
printf("Error; ");
if (auxfi)
fprintf(auxfi, "Error; ");
break;
case C_EXIT:
printf("Exit: ");
if (auxfi)
fprintf(auxfi, "Exit: ");
break;
case C_FLASH:
printf("\n");
break;
default:
break;
}
if (auxfi) {
fprintf(auxfi, "%s", buf);
}
if (auxfp)
putc(c, auxfp);
if (redir_fp)
fprintf(redir_fp, "%s", buf);
putc(c, redir_fp);
else if (pipe_fp)
fprintf(pipe_fp, "%s", buf);
else {
screen(buf);
}
}
static void
screen(char *buf)
{
char c;
while ((c = *buf++)) {
if (eight_bit_clean) {
if (c == 14)
putso();
else if (c == 15)
putse();
else
putchar(c);
} else if (c & 0x80) {
putc(c, pipe_fp);
else if (eight_bit_clean) {
if (c == 14)
putso();
putchar(c & 0x7f);
else if (c == 15)
putse();
} else
else
putchar(c);
}
} else if (c & 0x80) {
putso();
putchar(c & 0x7f);
putse();
} else
putchar(c);
}