Merge branch 'readline'
This commit is contained in:
commit
d3a64a4f6e
20 changed files with 479 additions and 200 deletions
7
Make.mk
7
Make.mk
|
@ -323,7 +323,7 @@ info.html/%.html: info/%.t
|
|||
$(server): $(filter src/server/% src/lib/commands/% src/lib/player/% src/lib/subs/% src/lib/update/%, $(obj)) $(empth_obj) $(empth_lib) $(libs)
|
||||
$(call quiet-command,$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@,LINK $@)
|
||||
|
||||
$(client): $(filter src/client/%, $(obj)) src/lib/global/version.o
|
||||
$(client): $(filter src/client/%, $(obj)) src/lib/global/version.o src/lib/gen/fnameat.o
|
||||
$(call quiet-command,$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@,LINK $@)
|
||||
|
||||
$(util): $(libs)
|
||||
|
@ -398,8 +398,9 @@ dist-client: $(cli_distgen)
|
|||
$(tarball) $(TARNAME)-client $(version) \
|
||||
-C $(srcdir)/src/client \
|
||||
$(notdir $(filter src/client/%, $(src)) $(cli_distgen)) \
|
||||
-C $(srcdir)/include proto.h version.h \
|
||||
-C $(srcdir)/include fnameat.h proto.h version.h \
|
||||
-C $(srcdir)/src/lib/global version.c \
|
||||
-C $(srcdir)/src/lib/gen fnameat.c \
|
||||
-C $(srcdir)/src/lib $(addprefix w32/, $(client/w32)) \
|
||||
-C $(srcdir)/man empire.6 \
|
||||
-C $(srcdir)/build-aux install-sh \
|
||||
|
@ -457,5 +458,5 @@ $(srcdir)/src/client/config.h.in: src/client/configure.ac src/client/aclocal.m4
|
|||
cd $(dir $@) && autoheader
|
||||
touch $@
|
||||
|
||||
$(srcdir)/src/client/aclocal.m4: m4/ax_lib_socket_nsl.m4 m4/my_terminfo.m4 m4/my_windows_api.m4
|
||||
$(srcdir)/src/client/aclocal.m4: m4/ax_lib_socket_nsl.m4 m4/my_lib_readline.m4 m4/my_terminfo.m4 m4/my_windows_api.m4
|
||||
cat $^ >$@
|
||||
|
|
|
@ -79,6 +79,7 @@ LIBS_util="$LIBS"
|
|||
LIBS="$LIBS_SOCKETS $LIBS"
|
||||
AX_LIB_SOCKET_NSL
|
||||
LIBS_server="$LIBS"
|
||||
MY_WITH_READLINE
|
||||
|
||||
|
||||
### Checks for header files
|
||||
|
@ -240,6 +241,7 @@ AC_OUTPUT
|
|||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([-= Configuration summary =-])
|
||||
AC_MSG_NOTICE([Thread package: $empthread])
|
||||
AC_MSG_NOTICE([ readline: $with_readline])
|
||||
AC_MSG_NOTICE([ terminfo: $with_terminfo])
|
||||
AC_MSG_NOTICE([ EMPIREHOST: $EMPIREHOST])
|
||||
AC_MSG_NOTICE([ EMPIREPORT: $EMPIREPORT])
|
||||
|
|
41
include/fnameat.h
Normal file
41
include/fnameat.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Empire - A multi-player, client/server Internet based war game.
|
||||
* Copyright (C) 1986-2015, Dave Pare, Jeff Bailey, Thomas Ruschak,
|
||||
* Ken Stevens, Steve McClure, Markus Armbruster
|
||||
*
|
||||
* Empire is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* See files README, COPYING and CREDITS in the root of the source
|
||||
* tree for related information and legal notices. It is expected
|
||||
* that future projects/authors will amend these files as needed.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* fnameat.h: Interpret file names relative to a directory
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Markus Armbruster, 2015
|
||||
*/
|
||||
|
||||
#ifndef FNAMEAT_H
|
||||
#define FNAMEAT_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
extern char *fnameat(const char *, const char *);
|
||||
extern FILE *fopenat(const char *, const char *, const char *);
|
||||
|
||||
#endif
|
|
@ -285,8 +285,7 @@ extern int demandupdatecheck(void);
|
|||
/* disassoc.c */
|
||||
extern int disassoc(void);
|
||||
/* fnameat.c */
|
||||
extern char *fnameat(const char *, const char *);
|
||||
extern FILE *fopenat(const char *, const char *, const char *);
|
||||
/* in fnameat.h */
|
||||
/* fsize.c */
|
||||
extern int fsize(int);
|
||||
extern int blksize(int);
|
||||
|
|
40
m4/my_lib_readline.m4
Normal file
40
m4/my_lib_readline.m4
Normal file
|
@ -0,0 +1,40 @@
|
|||
AC_DEFUN([MY_LIB_READLINE], [
|
||||
have_readline=no
|
||||
for readline_lib in readline edit editline; do
|
||||
for termcap_lib in "" termlib termcap curses ncurses; do
|
||||
AC_CHECK_LIB([$readline_lib], [add_history],
|
||||
[have_readline=yes; break 2], [], [$termcap_lib])
|
||||
done
|
||||
done
|
||||
|
||||
if test "$have_readline" = yes; then
|
||||
AC_CHECK_HEADER([readline/readline.h], [], [have_readline=no],
|
||||
[AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADER([readline/history.h], [], [have_readline=no],
|
||||
[AC_INCLUDES_DEFAULT])
|
||||
fi
|
||||
|
||||
if test "$have_readline" = yes; then
|
||||
if test "x$termcap_lib" != x; then
|
||||
LIBS="-l$termcap_lib $LIBS"
|
||||
fi
|
||||
LIBS="-l$readline_lib $LIBS"
|
||||
AC_DEFINE([HAVE_LIBREADLINE], [1],
|
||||
[Define if you have libreadline])
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([MY_WITH_READLINE],
|
||||
[
|
||||
AC_ARG_WITH([readline],
|
||||
[AS_HELP_STRING([--with-readline],
|
||||
[support fancy command line editing @<:@default=check@:>@])],
|
||||
[],
|
||||
[with_readline=check])
|
||||
if test "x$with_readline" != xno; then
|
||||
MY_LIB_READLINE
|
||||
if test "x$have_readline$with_readline" = xnoyes; then
|
||||
AC_MSG_FAILURE([--with-readline was given, but test for readline failed])
|
||||
fi
|
||||
with_readline="$have_readline"
|
||||
fi])
|
|
@ -14,11 +14,11 @@ AC_DEFUN([MY_WITH_TERMINFO],
|
|||
[
|
||||
AC_ARG_WITH([terminfo],
|
||||
AS_HELP_STRING([--with-terminfo],
|
||||
[use terminfo for highlighting (default check)]))
|
||||
[use terminfo for highlighting @<:@default check@:>@]))
|
||||
if test "x$with_terminfo" != xno; then
|
||||
MY_CURSES_TERMINFO
|
||||
if test "$have_terminfo$with_terminfo" = noyes
|
||||
then AC_MSG_FAILURE([Can't satisfy --with-terminfo])
|
||||
then AC_MSG_FAILURE([--with-terminfo was given, but test for terminfo failed])
|
||||
fi
|
||||
with_terminfo="$have_terminfo"
|
||||
fi
|
||||
|
|
29
man/empire.6
29
man/empire.6
|
@ -5,6 +5,7 @@ empire \- Empire client
|
|||
.B empire
|
||||
[\fB\-hkruv\fP]
|
||||
[\fB\-2\fP \fIoutfile\fP]
|
||||
[\fB\-H\fP \fIhistfile\fP]
|
||||
[\fB\-s\fP \fI[host:]port\fP]
|
||||
[\fIcountry\fP
|
||||
[\fIpassword\fP]]
|
||||
|
@ -24,11 +25,21 @@ the thin veneer of civilization that hides the maniac within.
|
|||
.B \-h
|
||||
Help. Print brief usage information and exit.
|
||||
.TP
|
||||
.BI \-H " histfile"
|
||||
Load command history from \fIhistfile\fP, and save it back. Default
|
||||
is '~/.empire_history' without \fB\-r\fP, and none with \fB-r\fP. You
|
||||
might want to protect your history file from prying eyes.
|
||||
.IP
|
||||
Only available when compiled the GNU \fBreadline\fP library.
|
||||
.TP
|
||||
.B \-k
|
||||
If someone else is connected to your country, kill their connection.
|
||||
.TP
|
||||
.B \-r
|
||||
Restricted mode: disable redirections and execute command.
|
||||
Restricted mode: disable redirections and execute command. This is
|
||||
useful when you want to grant somebody access to just Empire, but not
|
||||
to the host system's user account that runs the client. Be careful
|
||||
with \fB\-H\fP and \fB\-2\fP then.
|
||||
.TP
|
||||
.BI \-s " [host:]port"
|
||||
Specify server \fIhost\fR and \fIport\fR.
|
||||
|
@ -74,8 +85,21 @@ representative.
|
|||
.TP
|
||||
.I LOGNAME
|
||||
Your user name.
|
||||
.TP
|
||||
.I INPUTRC
|
||||
The filename for the \fBreadline\fP startup file, overriding the
|
||||
default of \fI~/.inputrc\fP (see \fBREADLINE\fP below).
|
||||
.SH READLINE
|
||||
When compiled with the GNU \fBreadline\fP library, the client supports
|
||||
fancy line editing and persistent history. Its application name for
|
||||
application-specific settings is \fBEmpire\fP. See the readline
|
||||
documentation for details.
|
||||
.SH "SEE ALSO"
|
||||
\fIemp_server\fR(6).
|
||||
\fIemp_server\fR(6), \fIreadline\fR(3).
|
||||
.SH FILES
|
||||
.TP
|
||||
.I ~/.inputrc
|
||||
Individual \fBreadline\fP initialization file
|
||||
.SH AUTHORS
|
||||
.nf
|
||||
Primary Author is Dave Pare <mr-frog@scam.berkeley.edu>
|
||||
|
@ -85,6 +109,7 @@ Jeff Anton <anton@postgres.berkeley.edu>
|
|||
Markus Armbruster <armbru@pond.sub.org>
|
||||
Phill Everson <everson@compsci.bristol.ac.uk>
|
||||
Steven Grimm <koreth@ucscb.UCSC.EDU>
|
||||
Martin Haukeli <martin.haukeli@gmail.com>
|
||||
Lewis R. Jansen <lrj@helios.tn.cornell.edu>
|
||||
Mike St. Johns <stjohns@edn-vax.arpa>
|
||||
Ron Koenderink <rkoenderink@yahoo.ca>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
# Makefile.in: Makefile template for configure
|
||||
#
|
||||
# Known contributors to this file:
|
||||
# Markus Armbruster, 2005-2013
|
||||
# Markus Armbruster, 2005-2015
|
||||
#
|
||||
|
||||
CC = @CC@
|
||||
|
@ -53,8 +53,9 @@ srcdir = @srcdir@
|
|||
VPATH = @srcdir@
|
||||
|
||||
prog = empire$E
|
||||
obj = expect.$O host.$O ipglob.$O linebuf.$O login.$O main.$O play.$O \
|
||||
ringbuf.$O secure.$O servcmd.$O termlib.$O version.$O $(LIBOBJS)
|
||||
obj = expect.$O fnameat.$O host.$O ipglob.$O linebuf.$O login.$O \
|
||||
main.$O play.$O ringbuf.$O secure.$O servcmd.$O termlib.$O version.$O \
|
||||
$(LIBOBJS)
|
||||
|
||||
all: $(prog)
|
||||
|
||||
|
@ -83,7 +84,7 @@ expect.$O: misc.h proto.h
|
|||
host.$O: misc.h
|
||||
linebuf.$O: linebuf.h
|
||||
login.$O: misc.h proto.h
|
||||
main.$O: misc.h version.h
|
||||
main.$O: fnameat.h misc.h version.h
|
||||
play.$O: linebuf.h misc.h proto.h ringbuf.h secure.h
|
||||
ringbuf.$O: ringbuf.h
|
||||
secure.$O: ringbuf.h secure.h
|
||||
|
|
|
@ -60,6 +60,7 @@ if test "$Windows_API" = yes; then
|
|||
AC_LIBOBJ([w32/w32io])
|
||||
AC_LIBOBJ([w32/w32sockets])
|
||||
fi
|
||||
MY_WITH_READLINE
|
||||
|
||||
|
||||
### Checks for header files.
|
||||
|
@ -97,6 +98,7 @@ AC_OUTPUT
|
|||
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([-= Configuration summary =-])
|
||||
AC_MSG_NOTICE([ readline: $with_readline])
|
||||
AC_MSG_NOTICE([ terminfo: $with_terminfo])
|
||||
AC_MSG_NOTICE([ EMPIREHOST: $EMPIREHOST])
|
||||
AC_MSG_NOTICE([ EMPIREPORT: $EMPIREPORT])
|
||||
|
|
|
@ -30,8 +30,9 @@
|
|||
* Dave Pare, 1986
|
||||
* Steve McClure, 1998
|
||||
* Ron Koenderink, 2004-2007
|
||||
* Markus Armbruster, 2005-2010
|
||||
* Markus Armbruster, 2005-2015
|
||||
* Tom Dickson-Hunt, 2010
|
||||
* Martin Haukeli, 2015
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
@ -40,11 +41,13 @@
|
|||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include "sys/socket.h"
|
||||
#else
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include "fnameat.h"
|
||||
#include "misc.h"
|
||||
#include "version.h"
|
||||
|
||||
|
@ -55,6 +58,7 @@
|
|||
|
||||
struct passwd {
|
||||
char *pw_name;
|
||||
char *pw_dir;
|
||||
};
|
||||
|
||||
static struct passwd *w32_getpw(void);
|
||||
|
@ -72,6 +76,10 @@ print_usage(char *program_name)
|
|||
" -r Restricted mode, no redirections\n"
|
||||
" -s [HOST:]PORT Specify server HOST and PORT\n"
|
||||
" -u Use UTF-8\n"
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
" -H FILE Load and save command history from FILE\n"
|
||||
" (default ~/.empire_history with -r, none without -r)\n"
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
" -h display this help and exit\n"
|
||||
" -v display version information and exit\n",
|
||||
program_name);
|
||||
|
@ -82,6 +90,7 @@ main(int argc, char **argv)
|
|||
{
|
||||
int opt;
|
||||
char *auxfname = NULL;
|
||||
char *history_file = NULL;
|
||||
int send_kill = 0;
|
||||
char *host = NULL;
|
||||
char *port = NULL;
|
||||
|
@ -90,14 +99,20 @@ main(int argc, char **argv)
|
|||
char *country;
|
||||
char *passwd;
|
||||
char *uname;
|
||||
char *udir;
|
||||
char *colon;
|
||||
int sock;
|
||||
|
||||
while ((opt = getopt(argc, argv, "2:krs:uhv")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "2:H:krs:uhv")) != EOF) {
|
||||
switch (opt) {
|
||||
case '2':
|
||||
auxfname = optarg;
|
||||
break;
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
case 'H':
|
||||
history_file = optarg;
|
||||
break;
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
case 'k':
|
||||
send_kill = 1;
|
||||
break;
|
||||
|
@ -146,7 +161,8 @@ main(int argc, char **argv)
|
|||
if (!host)
|
||||
host = empirehost;
|
||||
uname = getenv("LOGNAME");
|
||||
if (uname == NULL) {
|
||||
udir = getenv("HOME");
|
||||
if (!uname || !udir) {
|
||||
struct passwd *pwd;
|
||||
|
||||
pwd = getpwuid(getuid());
|
||||
|
@ -154,7 +170,10 @@ main(int argc, char **argv)
|
|||
fprintf(stderr, "You don't exist. Go away\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!uname)
|
||||
uname = pwd->pw_name;
|
||||
if (!udir)
|
||||
udir = pwd->pw_dir;
|
||||
}
|
||||
if (*ap) {
|
||||
fprintf(stderr, "%s: extra operand %s\n", argv[0], *ap);
|
||||
|
@ -172,10 +191,15 @@ main(int argc, char **argv)
|
|||
|
||||
sock = tcp_connect(host, port);
|
||||
|
||||
if (!restricted && !history_file)
|
||||
history_file = ".empire_history";
|
||||
if (history_file)
|
||||
history_file = fnameat(history_file, udir);
|
||||
|
||||
if (!login(sock, uname, country, passwd, send_kill, utf8))
|
||||
exit(1);
|
||||
|
||||
if (play(sock) < 0)
|
||||
if (play(sock, history_file) < 0)
|
||||
exit(1);
|
||||
|
||||
return 0;
|
||||
|
@ -183,12 +207,13 @@ main(int argc, char **argv)
|
|||
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
* Get Windows user name
|
||||
* Get Windows user name and directory
|
||||
*/
|
||||
static struct passwd *
|
||||
w32_getpw(void)
|
||||
{
|
||||
static char unamebuf[128];
|
||||
static char udirbuf[MAX_PATH];
|
||||
static struct passwd pwd;
|
||||
DWORD unamesize;
|
||||
|
||||
|
@ -199,6 +224,9 @@ w32_getpw(void)
|
|||
pwd.pw_name = "nobody";
|
||||
} else
|
||||
pwd.pw_name = "nobody";
|
||||
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, udirbuf))
|
||||
&& strlen(udirbuf) == 0)
|
||||
pwd.pw_dir = udirbuf;
|
||||
return &pwd;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
*
|
||||
* Known contributors to this file:
|
||||
* Steve McClure, 1998
|
||||
* Markus Armbruster, 2004-2017
|
||||
*/
|
||||
|
||||
#ifndef MISC_H
|
||||
|
@ -41,8 +42,6 @@
|
|||
extern char empirehost[];
|
||||
extern char empireport[];
|
||||
extern int eight_bit_clean;
|
||||
extern int input_fd;
|
||||
extern int send_eof;
|
||||
extern FILE *auxfp;
|
||||
extern int restricted;
|
||||
|
||||
|
@ -61,9 +60,10 @@ int parseid(char *);
|
|||
int expect(int s, int match, char *buf);
|
||||
int tcp_connect(char *, char *);
|
||||
int login(int s, char *uname, char *cname, char *cpass, int kill_proc, int);
|
||||
int play(int);
|
||||
int play(int, char *);
|
||||
void prompt(int, char *, char *);
|
||||
void sendcmd(int s, char *cmd, char *arg);
|
||||
void servercmd(int, char *, int);
|
||||
int servercmd(int, char *, int);
|
||||
void outch(char);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
|
@ -27,8 +27,9 @@
|
|||
* play.c: Playing the game
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Markus Armbruster, 2007-2010
|
||||
* Markus Armbruster, 2007-2017
|
||||
* Ron Koenderink, 2007-2009
|
||||
* Martin Haukeli, 2015
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
@ -51,6 +52,24 @@
|
|||
#include "ringbuf.h"
|
||||
#include "secure.h"
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#endif
|
||||
|
||||
#define EOF_COOKIE "ctld\n"
|
||||
#define INTR_COOKIE "aborted\n"
|
||||
|
||||
/*
|
||||
* Player input file descriptor
|
||||
* 0 while reading interactive input
|
||||
* >0 while reading a batch file
|
||||
* <0 during error handling
|
||||
*/
|
||||
static int input_fd;
|
||||
|
||||
static volatile sig_atomic_t send_intr; /* need to send INTR_COOKIE */
|
||||
|
||||
#ifdef _WIN32
|
||||
static CRITICAL_SECTION signal_critical_section;
|
||||
static LPCRITICAL_SECTION signal_critical_section_ptr = NULL;
|
||||
|
@ -301,13 +320,6 @@ w32_ring_from_file_or_bounce_buf(struct ring *r, int fd)
|
|||
#define sysdep_stdin_init() ((void)0)
|
||||
#endif
|
||||
|
||||
#define EOF_COOKIE "ctld\n"
|
||||
#define INTR_COOKIE "aborted\n"
|
||||
|
||||
int input_fd;
|
||||
int send_eof; /* need to send EOF_COOKIE */
|
||||
static volatile sig_atomic_t send_intr; /* need to send INTR_COOKIE */
|
||||
|
||||
/*
|
||||
* Receive and process server output from @sock.
|
||||
* Return number of characters received on success, -1 on error.
|
||||
|
@ -335,7 +347,7 @@ recv_output(int sock)
|
|||
static struct lbuf lbuf;
|
||||
char buf[4096];
|
||||
ssize_t n;
|
||||
int i, ch, len;
|
||||
int i, ch, len, fd;
|
||||
char *line;
|
||||
|
||||
n = read(sock, buf, sizeof(buf));
|
||||
|
@ -381,7 +393,18 @@ recv_output(int sock)
|
|||
len = lbuf_putc(&lbuf, ch);
|
||||
if (len) {
|
||||
line = lbuf_line(&lbuf);
|
||||
servercmd(id, line, len);
|
||||
fd = servercmd(id, line, len);
|
||||
if (fd < 0) {
|
||||
/* failed execute */
|
||||
if (input_fd)
|
||||
close(input_fd);
|
||||
input_fd = 0;
|
||||
send_intr = 1;
|
||||
} else if (fd > 0) {
|
||||
/* successful execute, switch to batch file */
|
||||
assert(!input_fd);
|
||||
input_fd = fd;
|
||||
}
|
||||
lbuf_init(&lbuf);
|
||||
state = SCANNING_ID;
|
||||
}
|
||||
|
@ -397,28 +420,73 @@ recv_output(int sock)
|
|||
return n;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
static int use_readline;
|
||||
static char *input_from_rl;
|
||||
static int has_rl_input;
|
||||
|
||||
static void
|
||||
input_handler(char *line)
|
||||
{
|
||||
input_from_rl = line;
|
||||
has_rl_input = 1;
|
||||
if (line && *line)
|
||||
add_history(line);
|
||||
}
|
||||
|
||||
static int
|
||||
ring_from_rl(struct ring *inbuf)
|
||||
{
|
||||
size_t len;
|
||||
int n;
|
||||
|
||||
assert(has_rl_input && input_from_rl);
|
||||
|
||||
len = strlen(input_from_rl);
|
||||
n = ring_space(inbuf);
|
||||
assert(n);
|
||||
|
||||
if (len >= (size_t)n) {
|
||||
ring_putm(inbuf, input_from_rl, n);
|
||||
memmove(input_from_rl, input_from_rl + n, len - n + 1);
|
||||
} else {
|
||||
ring_putm(inbuf, input_from_rl, len);
|
||||
ring_putc(inbuf, '\n');
|
||||
free(input_from_rl);
|
||||
has_rl_input = 0;
|
||||
n = len + 1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
/*
|
||||
* Receive command input from @fd into @inbuf.
|
||||
* Receive player input from @fd into @inbuf.
|
||||
* Return 1 on receipt of input, zero on EOF, -1 on error.
|
||||
*/
|
||||
static int
|
||||
recv_input(int fd, struct ring *inbuf)
|
||||
{
|
||||
static struct lbuf cmdbuf;
|
||||
int n, i, ch;
|
||||
char *line;
|
||||
int n;
|
||||
int res = 1;
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (fd == 0 && use_readline) {
|
||||
if (!has_rl_input)
|
||||
rl_callback_read_char();
|
||||
if (!has_rl_input)
|
||||
return 1;
|
||||
if (input_from_rl) {
|
||||
n = ring_from_rl(inbuf);
|
||||
} else
|
||||
n = 0;
|
||||
} else
|
||||
#endif
|
||||
n = ring_from_file(inbuf, fd);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
if (n == 0) {
|
||||
/* EOF on input */
|
||||
if (lbuf_len(&cmdbuf)) {
|
||||
/* incomplete line */
|
||||
ring_putc(inbuf, '\n');
|
||||
n++;
|
||||
}
|
||||
/*
|
||||
* Can't put EOF cookie into INBUF here, it may not fit.
|
||||
* Leave it to caller.
|
||||
|
@ -426,19 +494,36 @@ recv_input(int fd, struct ring *inbuf)
|
|||
res = 0;
|
||||
}
|
||||
|
||||
/* copy input to AUXFP etc. */
|
||||
for (i = -n; i < 0; i++) {
|
||||
ch = ring_peek(inbuf, i);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
send_input(int fd, struct ring *inbuf)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
int cnt, i, ch;
|
||||
ssize_t res;
|
||||
|
||||
cnt = ring_to_iovec(inbuf, iov);
|
||||
res = writev(fd, iov, cnt);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
/* Copy input to @auxfp etc. */
|
||||
for (i = 0; i < res; i++) {
|
||||
ch = ring_getc(inbuf);
|
||||
assert(ch != EOF);
|
||||
if (ch != '\r' && lbuf_putc(&cmdbuf, ch) > 0) {
|
||||
line = lbuf_line(&cmdbuf);
|
||||
save_input(line);
|
||||
lbuf_init(&cmdbuf);
|
||||
}
|
||||
if (ch != '\r')
|
||||
save_input(ch);
|
||||
if (auxfp)
|
||||
putc(ch, auxfp);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (fd == 0 && use_readline && has_rl_input && input_from_rl)
|
||||
ring_from_rl(inbuf);
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -450,11 +535,12 @@ intr(int sig)
|
|||
|
||||
/*
|
||||
* Play on @sock.
|
||||
* @history_file is the name of the history file, or null.
|
||||
* The session must be in the playing phase.
|
||||
* Return 0 when the session ended, -1 on error.
|
||||
*/
|
||||
int
|
||||
play(int sock)
|
||||
play(int sock, char *history_file)
|
||||
{
|
||||
/*
|
||||
* Player input flows from INPUT_FD through recv_input() into ring
|
||||
|
@ -466,8 +552,10 @@ play(int sock)
|
|||
struct ring inbuf; /* input buffer, draining to SOCK */
|
||||
int eof_fd0; /* read fd 0 hit EOF? */
|
||||
int partial_line_sent; /* partial input line sent? */
|
||||
int send_eof; /* need to send EOF_COOKIE */
|
||||
fd_set rdfd, wrfd;
|
||||
int n;
|
||||
int ret = -1;
|
||||
|
||||
sa.sa_flags = 0;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
@ -475,6 +563,17 @@ play(int sock)
|
|||
sigaction(SIGINT, &sa, NULL);
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sa, NULL);
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (isatty(0)) {
|
||||
use_readline = 1;
|
||||
rl_already_prompted = 1;
|
||||
rl_readline_name = "Empire";
|
||||
if (history_file)
|
||||
read_history(history_file);
|
||||
rl_bind_key('\t', rl_insert); /* Disable tab completion */
|
||||
rl_callback_handler_install("", input_handler);
|
||||
}
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
ring_init(&inbuf);
|
||||
eof_fd0 = partial_line_sent = send_eof = send_intr = 0;
|
||||
|
@ -487,10 +586,11 @@ play(int sock)
|
|||
|
||||
/*
|
||||
* Want to read player input only when we don't need to send
|
||||
* cookies, and INPUT_FD is still open, and INBUF can accept
|
||||
* cookies, haven't reached EOF on fd 0, and @inbuf can accept
|
||||
* some.
|
||||
*/
|
||||
if (!send_intr && !send_eof && input_fd >= 0 && ring_space(&inbuf))
|
||||
if (!send_intr && !send_eof && (input_fd || !eof_fd0)
|
||||
&& ring_space(&inbuf))
|
||||
FD_SET(input_fd, &rdfd);
|
||||
/* Want to send player input only when we have something */
|
||||
if (send_intr || send_eof || ring_len(&inbuf))
|
||||
|
@ -502,7 +602,7 @@ play(int sock)
|
|||
if (n < 0) {
|
||||
if (errno != EINTR) {
|
||||
perror("select");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,51 +611,52 @@ play(int sock)
|
|||
partial_line_sent = 0;
|
||||
if (send_eof && !partial_line_sent
|
||||
&& ring_putm(&inbuf, EOF_COOKIE, sizeof(EOF_COOKIE) - 1) >= 0)
|
||||
send_eof--;
|
||||
send_eof = 0;
|
||||
if (send_intr && !partial_line_sent
|
||||
&& ring_putm(&inbuf, INTR_COOKIE, sizeof(INTR_COOKIE) - 1) >= 0) {
|
||||
send_intr = 0;
|
||||
if (input_fd) {
|
||||
/* execute aborted, switch back to fd 0 */
|
||||
close(input_fd);
|
||||
input_fd = eof_fd0 ? -1 : 0;
|
||||
input_fd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
continue;
|
||||
|
||||
/* read player input */
|
||||
if (input_fd >= 0 && FD_ISSET(input_fd, &rdfd)) {
|
||||
if (FD_ISSET(input_fd, &rdfd) && ring_space(&inbuf)) {
|
||||
n = recv_input(input_fd, &inbuf);
|
||||
if (n < 0) {
|
||||
perror("read stdin"); /* FIXME stdin misleading, could be execing */
|
||||
n = 0;
|
||||
}
|
||||
if (n == 0) {
|
||||
/* EOF on input */
|
||||
send_eof++;
|
||||
if (n <= 0) {
|
||||
if (input_fd) {
|
||||
/* execute done, switch back to fd 0 */
|
||||
if (n < 0) {
|
||||
perror("read batch file");
|
||||
send_intr = 1;
|
||||
} else
|
||||
send_eof = 1;
|
||||
close(input_fd);
|
||||
input_fd = eof_fd0 ? -1 : 0;
|
||||
input_fd = 0;
|
||||
} else {
|
||||
/* stop reading input, drain socket ring buffers */
|
||||
if (n < 0)
|
||||
perror("read stdin");
|
||||
send_eof = 1;
|
||||
eof_fd0 = 1;
|
||||
input_fd = -1;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
send_intr = 0;
|
||||
}
|
||||
} else
|
||||
} else if (ring_len(&inbuf) > 0)
|
||||
partial_line_sent = ring_peek(&inbuf, -1) != '\n';
|
||||
}
|
||||
|
||||
/* send it to the server */
|
||||
if (FD_ISSET(sock, &wrfd)) {
|
||||
n = ring_to_file(&inbuf, sock);
|
||||
n = send_input(sock, &inbuf);
|
||||
if (n < 0) {
|
||||
perror("write socket");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,10 +665,43 @@ play(int sock)
|
|||
n = recv_output(sock);
|
||||
if (n < 0) {
|
||||
perror("read socket");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
if (n == 0)
|
||||
return 0;
|
||||
if (n == 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (use_readline) {
|
||||
rl_callback_handler_remove();
|
||||
if (history_file)
|
||||
write_history(history_file);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
prompt(int code, char *prompt, char *teles)
|
||||
{
|
||||
char pr[1024];
|
||||
|
||||
snprintf(pr, sizeof(pr), "%s%s", teles, prompt);
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (use_readline) {
|
||||
rl_set_prompt(pr);
|
||||
rl_forced_update_display();
|
||||
} else
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
{
|
||||
printf("%s", pr);
|
||||
fflush(stdout);
|
||||
}
|
||||
if (auxfp) {
|
||||
fprintf(auxfp, "%s%s", teles, prompt);
|
||||
fflush(auxfp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
* ringbuf.c: Simple ring buffer
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Markus Armbruster, 2007-2009
|
||||
* Markus Armbruster, 2007-2017
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
@ -35,7 +35,6 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include "ringbuf.h"
|
||||
|
||||
/*
|
||||
|
@ -82,9 +81,17 @@ ring_peek(struct ring *r, int n)
|
|||
|
||||
assert(-RING_SIZE - 1 <= n && n <= RING_SIZE);
|
||||
|
||||
idx = n >= 0 ? r->cons + n : r->prod - -n;
|
||||
if (idx < r->cons && idx >= r->prod)
|
||||
if (n >= 0) {
|
||||
idx = r->cons + n;
|
||||
if (idx >= r->prod)
|
||||
return EOF;
|
||||
} else {
|
||||
/* Beware, r->prod - -n can wrap around, avoid that */
|
||||
if (r->prod < r->cons + -n)
|
||||
return EOF;
|
||||
idx = r->prod - -n;
|
||||
}
|
||||
|
||||
return r->buf[idx % RING_SIZE];
|
||||
}
|
||||
|
||||
|
@ -149,16 +156,17 @@ ring_discard(struct ring *r, int n)
|
|||
|
||||
/*
|
||||
* Search the ring buffer for zero-terminated string S.
|
||||
* If found, return a non-negative value referring to the beginning of
|
||||
* S in the buffer when passed to ring_peek(). Else return -1.
|
||||
* Start at the @(n+1)-th byte to be gotten.
|
||||
* If found, return the number of bytes in the buffer before S.
|
||||
* Else return -1.
|
||||
*/
|
||||
int
|
||||
ring_search(struct ring *r, char *s)
|
||||
ring_search(struct ring *r, char *s, int n)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
size_t i, j;
|
||||
|
||||
for (i = r->cons; i + len <= r->prod; i++) {
|
||||
for (i = r->cons + n; i + len <= r->prod; i++) {
|
||||
for (j = 0; s[j] && s[j] == (char)r->buf[(i + j) % RING_SIZE]; j++)
|
||||
;
|
||||
if (!s[j])
|
||||
|
@ -206,39 +214,29 @@ ring_from_file(struct ring *r, int fd)
|
|||
}
|
||||
|
||||
/*
|
||||
* Drain ring buffer to file referred by file descriptor @fd.
|
||||
* If ring buffer is already empty, do nothing and return 0.
|
||||
* Else attempt to write complete contents with writev(), and return
|
||||
* its value.
|
||||
* Set up @iov[] to describe complete contents of ring buffer.
|
||||
* @iov[] must have at least two elements.
|
||||
* Return number of elements used (zero for an empty ring buffer).
|
||||
*/
|
||||
int
|
||||
ring_to_file(struct ring *r, int fd)
|
||||
ring_to_iovec(struct ring *r, struct iovec iov[])
|
||||
{
|
||||
unsigned cons = r->cons % RING_SIZE;
|
||||
unsigned prod = r->prod % RING_SIZE;
|
||||
struct iovec iov[2];
|
||||
int cnt;
|
||||
ssize_t res;
|
||||
|
||||
if (r->cons == r->prod)
|
||||
return 0;
|
||||
|
||||
iov[0].iov_base = r->buf + cons;
|
||||
if (prod <= cons) {
|
||||
if (prod > cons) {
|
||||
/* r->buf[cons..prod-1] */
|
||||
iov[0].iov_len = prod - cons;
|
||||
return 1;
|
||||
}
|
||||
/* r->buf[cons..] */
|
||||
iov[0].iov_len = RING_SIZE - cons;
|
||||
/* r->buf[..prod-1] */
|
||||
iov[1].iov_base = r->buf;
|
||||
iov[1].iov_len = prod;
|
||||
cnt = 2;
|
||||
} else {
|
||||
/* r->buf[cons..prod-1] */
|
||||
iov[0].iov_len = prod - cons;
|
||||
cnt = 1;
|
||||
}
|
||||
res = writev(fd, iov, cnt);
|
||||
if (res < 0)
|
||||
return res;
|
||||
r->cons += res;
|
||||
return res;
|
||||
return 2;
|
||||
}
|
||||
|
|
|
@ -27,13 +27,14 @@
|
|||
* ringbuf.h: Simple ring buffer
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Markus Armbruster, 2007
|
||||
* Markus Armbruster, 2007-2017
|
||||
*/
|
||||
|
||||
#ifndef RINGBUF_H
|
||||
#define RINGBUF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#define RING_SIZE 4096
|
||||
|
||||
|
@ -59,8 +60,8 @@ extern int ring_getc(struct ring *);
|
|||
extern int ring_putc(struct ring *, unsigned char);
|
||||
extern int ring_putm(struct ring *, void *, size_t);
|
||||
extern void ring_discard(struct ring *, int);
|
||||
extern int ring_search(struct ring *, char *);
|
||||
extern int ring_search(struct ring *, char *, int);
|
||||
extern int ring_from_file(struct ring *, int fd);
|
||||
extern int ring_to_file(struct ring *, int fd);
|
||||
extern int ring_to_iovec(struct ring *, struct iovec[]);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,79 +27,81 @@
|
|||
* secure.c: Check redir etc. to protect against tampering deity
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Markus Armbruster, 2007
|
||||
* Markus Armbruster, 2007-2017
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "ringbuf.h"
|
||||
#include "secure.h"
|
||||
|
||||
static struct ring recent_input;
|
||||
static size_t saved_bytes;
|
||||
|
||||
/*
|
||||
* Remember line of input @inp for a while.
|
||||
* It must end with a newline.
|
||||
* Return value is suitable for forget_input(): it makes it forget all
|
||||
* input up to and including this line.
|
||||
* Remember input @inp for a while.
|
||||
*/
|
||||
size_t
|
||||
save_input(char *inp)
|
||||
void
|
||||
save_input(char inp)
|
||||
{
|
||||
size_t len = strlen(inp);
|
||||
int eol;
|
||||
|
||||
assert(len && inp[len - 1] == '\n');
|
||||
|
||||
while (ring_putm(&recent_input, inp, len) < 0) {
|
||||
eol = ring_search(&recent_input, "\n");
|
||||
while (ring_putc(&recent_input, inp) < 0) {
|
||||
eol = ring_search(&recent_input, "\n", 0);
|
||||
assert(eol >= 0);
|
||||
ring_discard(&recent_input, eol + 1);
|
||||
}
|
||||
saved_bytes += len;
|
||||
return saved_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can you still remember a line of input that ends with @tail?
|
||||
* It must end with a newline.
|
||||
* Return non-zero iff @tail can be remembered.
|
||||
* Passing that value to forget_input() will forget all input up to
|
||||
* and including this line.
|
||||
*/
|
||||
size_t
|
||||
int
|
||||
seen_input(char *tail)
|
||||
{
|
||||
size_t len = strlen(tail);
|
||||
size_t remembered = ring_len(&recent_input);
|
||||
int dist;
|
||||
|
||||
assert(len && tail[len - 1] == '\n');
|
||||
|
||||
dist = ring_search(&recent_input, tail);
|
||||
if (dist < 0)
|
||||
return 0;
|
||||
|
||||
assert(dist + len <= remembered && remembered <= saved_bytes);
|
||||
return saved_bytes - remembered + dist + len;
|
||||
return ring_search(&recent_input, tail, 0) >= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forget remembered input up to @seen.
|
||||
* @seen should be obtained from save_input() or seen_input().
|
||||
* Can you still remember input that looks like an execute @arg?
|
||||
* @arg must end with a newline.
|
||||
*/
|
||||
void
|
||||
forget_input(size_t seen)
|
||||
int
|
||||
seen_exec_input(char *arg)
|
||||
{
|
||||
size_t forgotten = saved_bytes - ring_len(&recent_input);
|
||||
size_t len = strlen(arg);
|
||||
int n, i, j, ch;
|
||||
unsigned char buf[RING_SIZE + 1];
|
||||
|
||||
assert(seen);
|
||||
assert(len && arg[len - 1] == '\n');
|
||||
|
||||
if (seen > forgotten) {
|
||||
assert(ring_peek(&recent_input, seen - forgotten - 1) == '\n');
|
||||
ring_discard(&recent_input, seen - forgotten);
|
||||
n = 1;
|
||||
for (;;) {
|
||||
/* find next line ending with arg */
|
||||
n = ring_search(&recent_input, arg, n + 1);
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
|
||||
/* extract command (same or previous line) */
|
||||
i = n - 1;
|
||||
if (ring_peek(&recent_input, i) == '\n')
|
||||
i--;
|
||||
j = sizeof(buf);
|
||||
buf[--j] = 0;
|
||||
for (; i >= 0 && (ch = ring_peek(&recent_input, i)) != '\n'; i--)
|
||||
buf[--j] = ch;
|
||||
|
||||
/* compare command */
|
||||
for (; isspace(buf[j]); j++) ;
|
||||
for (i = j; buf[i] && !isspace(buf[i]); i++) ;
|
||||
if (i - j >= 2 && !strncmp("execute", (char *)buf + j, i - j))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
* secure.h: Check redir etc. to protect against tampering deity
|
||||
*
|
||||
* Known contributors to this file:
|
||||
* Markus Armbruster, 2007-2009
|
||||
* Markus Armbruster, 2007-2017
|
||||
*/
|
||||
|
||||
#ifndef SECURE_H
|
||||
|
@ -35,8 +35,8 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
extern size_t save_input(char *);
|
||||
extern size_t seen_input(char *);
|
||||
extern void forget_input(size_t);
|
||||
extern void save_input(char);
|
||||
extern int seen_input(char *);
|
||||
extern int seen_exec_input(char *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
* Dave Pare, 1989
|
||||
* Steve McClure, 1998
|
||||
* Ron Koenderink, 2005
|
||||
* Markus Armbruster, 2005-2010
|
||||
* Markus Armbruster, 2005-2017
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
@ -41,6 +41,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "misc.h"
|
||||
#include "proto.h"
|
||||
#include "secure.h"
|
||||
|
@ -52,14 +53,12 @@ int restricted;
|
|||
static FILE *redir_fp;
|
||||
static int redir_is_pipe;
|
||||
static int executing;
|
||||
static size_t input_to_forget;
|
||||
|
||||
static void prompt(int, char *, char *);
|
||||
static void doredir(char *p);
|
||||
static void dopipe(char *p);
|
||||
static int doexecute(char *p);
|
||||
|
||||
void
|
||||
int
|
||||
servercmd(int code, char *arg, int len)
|
||||
{
|
||||
static int nmin, nbtu, fd;
|
||||
|
@ -69,7 +68,8 @@ servercmd(int code, char *arg, int len)
|
|||
switch (code) {
|
||||
case C_PROMPT:
|
||||
if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
|
||||
fprintf(stderr, "prompt: bad server prompt %s\n", arg);
|
||||
fprintf(stderr, "Warning: server sent malformed prompt %s",
|
||||
arg);
|
||||
}
|
||||
snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
|
||||
nmin, nbtu);
|
||||
|
@ -80,10 +80,7 @@ servercmd(int code, char *arg, int len)
|
|||
(void)fclose(redir_fp);
|
||||
redir_fp = NULL;
|
||||
}
|
||||
if (input_to_forget) {
|
||||
forget_input(input_to_forget);
|
||||
input_to_forget = 0;
|
||||
}
|
||||
outch('\n');
|
||||
prompt(code, the_prompt, teles);
|
||||
executing = 0;
|
||||
break;
|
||||
|
@ -93,13 +90,9 @@ servercmd(int code, char *arg, int len)
|
|||
break;
|
||||
case C_EXECUTE:
|
||||
fd = doexecute(arg);
|
||||
if (fd < 0)
|
||||
send_eof++;
|
||||
else {
|
||||
input_fd = fd;
|
||||
if (fd >= 0)
|
||||
executing = 1;
|
||||
}
|
||||
break;
|
||||
return fd;
|
||||
case C_EXIT:
|
||||
printf("Exit: %s", arg);
|
||||
if (auxfp)
|
||||
|
@ -114,6 +107,7 @@ servercmd(int code, char *arg, int len)
|
|||
if (arg[0] != '\n') {
|
||||
snprintf(teles, sizeof(teles), "(%.*s) ", len - 1, arg);
|
||||
if (!redir_fp) {
|
||||
outch('\n');
|
||||
putchar('\07');
|
||||
prompt(code, the_prompt, teles);
|
||||
}
|
||||
|
@ -130,20 +124,8 @@ servercmd(int code, char *arg, int len)
|
|||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
prompt(int code, char *prompt, char *teles)
|
||||
{
|
||||
char *nl;
|
||||
|
||||
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);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -158,10 +140,8 @@ fname(char *s)
|
|||
}
|
||||
|
||||
static int
|
||||
redir_authorized(char *arg, char *attempt, int expected)
|
||||
common_authorized(char *arg, char *attempt)
|
||||
{
|
||||
size_t seen = seen_input(arg);
|
||||
|
||||
if (restricted) {
|
||||
fprintf(stderr, "Can't %s in restricted mode\n", attempt);
|
||||
return 0;
|
||||
|
@ -171,20 +151,37 @@ redir_authorized(char *arg, char *attempt, int expected)
|
|||
fprintf(stderr, "Can't %s in a batch file\n", attempt);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!expected) {
|
||||
fprintf(stderr, "WARNING! Server attempted to %s unexpectedly\n",
|
||||
attempt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!seen || (input_to_forget && input_to_forget != seen)) {
|
||||
fprintf(stderr, "WARNING! Server attempted to %s %s\n",
|
||||
static int
|
||||
redir_authorized(char *arg, char *attempt)
|
||||
{
|
||||
if (redir_fp) {
|
||||
fprintf(stderr, "Warning: dropped conflicting %s %s",
|
||||
attempt, arg);
|
||||
return 0;
|
||||
}
|
||||
input_to_forget = seen;
|
||||
return 1;
|
||||
|
||||
if (!seen_input(arg)) {
|
||||
fprintf(stderr, "Warning: server attempted to %s %s",
|
||||
attempt, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return common_authorized(arg, attempt);
|
||||
}
|
||||
|
||||
static int
|
||||
exec_authorized(char *arg)
|
||||
{
|
||||
if (!seen_exec_input(arg)) {
|
||||
fprintf(stderr,
|
||||
"Warning: server attempted to execute batch file %s", arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return common_authorized(arg, "execute batch file");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -193,10 +190,10 @@ doredir(char *p)
|
|||
int mode;
|
||||
int fd;
|
||||
|
||||
if (!redir_authorized(p, "redirect to file", !redir_fp))
|
||||
if (!redir_authorized(p, "redirect to file"))
|
||||
return;
|
||||
if (*p++ != '>') {
|
||||
fprintf(stderr, "WARNING! Weird redirection %s", p);
|
||||
fprintf(stderr, "Warning: dropped weird redirection %s", p);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -228,10 +225,10 @@ doredir(char *p)
|
|||
static void
|
||||
dopipe(char *p)
|
||||
{
|
||||
if (!redir_authorized(p, "pipe to shell command", !redir_fp))
|
||||
if (!redir_authorized(p, "pipe to shell command"))
|
||||
return;
|
||||
if (*p++ != '|') {
|
||||
fprintf(stderr, "WARNING! Weird pipe %s", p);
|
||||
fprintf(stderr, "Warning: dropped weird pipe %s", p);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -241,10 +238,14 @@ dopipe(char *p)
|
|||
return;
|
||||
}
|
||||
|
||||
/* strip newline */
|
||||
p[strlen(p) - 1] = 0;
|
||||
|
||||
redir_is_pipe = 1;
|
||||
errno = 0;
|
||||
if ((redir_fp = popen(p, "w")) == NULL) {
|
||||
fprintf(stderr, "Can't redirect to pipe %s: %s\n",
|
||||
p, strerror(errno));
|
||||
fprintf(stderr, "Can't redirect to pipe %s%s%s\n",
|
||||
p, errno ? ": " : "", errno ? strerror(errno) : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +254,7 @@ doexecute(char *p)
|
|||
{
|
||||
int fd;
|
||||
|
||||
if (!redir_authorized(p, "execute batch file", 1))
|
||||
if (!exec_authorized(p))
|
||||
return -1;
|
||||
|
||||
p = fname(p);
|
||||
|
@ -263,7 +264,7 @@ doexecute(char *p)
|
|||
}
|
||||
|
||||
if ((fd = open(p, O_RDONLY)) < 0) {
|
||||
fprintf(stderr, "Can't open execute file %s: %s\n",
|
||||
fprintf(stderr, "Can't open batch file %s: %s\n",
|
||||
p, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "file.h"
|
||||
#include "fnameat.h"
|
||||
#include "optlist.h"
|
||||
#include "prototypes.h"
|
||||
#include "xdump.h"
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fnameat.h"
|
||||
#include "misc.h"
|
||||
#include "optlist.h"
|
||||
#include "prototypes.h"
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include "prototypes.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fnameat.h"
|
||||
|
||||
static int fname_is_abs(const char *);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue