Merge branch 'readline'

This commit is contained in:
Markus Armbruster 2017-07-08 20:43:29 +02:00
commit d3a64a4f6e
20 changed files with 479 additions and 200 deletions

View file

@ -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) $(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 $@) $(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 $@) $(call quiet-command,$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@,LINK $@)
$(util): $(libs) $(util): $(libs)
@ -398,8 +398,9 @@ dist-client: $(cli_distgen)
$(tarball) $(TARNAME)-client $(version) \ $(tarball) $(TARNAME)-client $(version) \
-C $(srcdir)/src/client \ -C $(srcdir)/src/client \
$(notdir $(filter src/client/%, $(src)) $(cli_distgen)) \ $(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/global version.c \
-C $(srcdir)/src/lib/gen fnameat.c \
-C $(srcdir)/src/lib $(addprefix w32/, $(client/w32)) \ -C $(srcdir)/src/lib $(addprefix w32/, $(client/w32)) \
-C $(srcdir)/man empire.6 \ -C $(srcdir)/man empire.6 \
-C $(srcdir)/build-aux install-sh \ -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 cd $(dir $@) && autoheader
touch $@ 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 $^ >$@ cat $^ >$@

View file

@ -79,6 +79,7 @@ LIBS_util="$LIBS"
LIBS="$LIBS_SOCKETS $LIBS" LIBS="$LIBS_SOCKETS $LIBS"
AX_LIB_SOCKET_NSL AX_LIB_SOCKET_NSL
LIBS_server="$LIBS" LIBS_server="$LIBS"
MY_WITH_READLINE
### Checks for header files ### Checks for header files
@ -240,6 +241,7 @@ AC_OUTPUT
AC_MSG_NOTICE([]) AC_MSG_NOTICE([])
AC_MSG_NOTICE([-= Configuration summary =-]) AC_MSG_NOTICE([-= Configuration summary =-])
AC_MSG_NOTICE([Thread package: $empthread]) AC_MSG_NOTICE([Thread package: $empthread])
AC_MSG_NOTICE([ readline: $with_readline])
AC_MSG_NOTICE([ terminfo: $with_terminfo]) AC_MSG_NOTICE([ terminfo: $with_terminfo])
AC_MSG_NOTICE([ EMPIREHOST: $EMPIREHOST]) AC_MSG_NOTICE([ EMPIREHOST: $EMPIREHOST])
AC_MSG_NOTICE([ EMPIREPORT: $EMPIREPORT]) AC_MSG_NOTICE([ EMPIREPORT: $EMPIREPORT])

41
include/fnameat.h Normal file
View 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

View file

@ -285,8 +285,7 @@ extern int demandupdatecheck(void);
/* disassoc.c */ /* disassoc.c */
extern int disassoc(void); extern int disassoc(void);
/* fnameat.c */ /* fnameat.c */
extern char *fnameat(const char *, const char *); /* in fnameat.h */
extern FILE *fopenat(const char *, const char *, const char *);
/* fsize.c */ /* fsize.c */
extern int fsize(int); extern int fsize(int);
extern int blksize(int); extern int blksize(int);

40
m4/my_lib_readline.m4 Normal file
View 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])

View file

@ -14,11 +14,11 @@ AC_DEFUN([MY_WITH_TERMINFO],
[ [
AC_ARG_WITH([terminfo], AC_ARG_WITH([terminfo],
AS_HELP_STRING([--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 if test "x$with_terminfo" != xno; then
MY_CURSES_TERMINFO MY_CURSES_TERMINFO
if test "$have_terminfo$with_terminfo" = noyes 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 fi
with_terminfo="$have_terminfo" with_terminfo="$have_terminfo"
fi fi

View file

@ -5,6 +5,7 @@ empire \- Empire client
.B empire .B empire
[\fB\-hkruv\fP] [\fB\-hkruv\fP]
[\fB\-2\fP \fIoutfile\fP] [\fB\-2\fP \fIoutfile\fP]
[\fB\-H\fP \fIhistfile\fP]
[\fB\-s\fP \fI[host:]port\fP] [\fB\-s\fP \fI[host:]port\fP]
[\fIcountry\fP [\fIcountry\fP
[\fIpassword\fP]] [\fIpassword\fP]]
@ -24,11 +25,21 @@ the thin veneer of civilization that hides the maniac within.
.B \-h .B \-h
Help. Print brief usage information and exit. Help. Print brief usage information and exit.
.TP .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 .B \-k
If someone else is connected to your country, kill their connection. If someone else is connected to your country, kill their connection.
.TP .TP
.B \-r .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 .TP
.BI \-s " [host:]port" .BI \-s " [host:]port"
Specify server \fIhost\fR and \fIport\fR. Specify server \fIhost\fR and \fIport\fR.
@ -74,8 +85,21 @@ representative.
.TP .TP
.I LOGNAME .I LOGNAME
Your user name. 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" .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 .SH AUTHORS
.nf .nf
Primary Author is Dave Pare <mr-frog@scam.berkeley.edu> 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> Markus Armbruster <armbru@pond.sub.org>
Phill Everson <everson@compsci.bristol.ac.uk> Phill Everson <everson@compsci.bristol.ac.uk>
Steven Grimm <koreth@ucscb.UCSC.EDU> Steven Grimm <koreth@ucscb.UCSC.EDU>
Martin Haukeli <martin.haukeli@gmail.com>
Lewis R. Jansen <lrj@helios.tn.cornell.edu> Lewis R. Jansen <lrj@helios.tn.cornell.edu>
Mike St. Johns <stjohns@edn-vax.arpa> Mike St. Johns <stjohns@edn-vax.arpa>
Ron Koenderink <rkoenderink@yahoo.ca> Ron Koenderink <rkoenderink@yahoo.ca>

View file

@ -28,7 +28,7 @@
# Makefile.in: Makefile template for configure # Makefile.in: Makefile template for configure
# #
# Known contributors to this file: # Known contributors to this file:
# Markus Armbruster, 2005-2013 # Markus Armbruster, 2005-2015
# #
CC = @CC@ CC = @CC@
@ -53,8 +53,9 @@ srcdir = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
prog = empire$E prog = empire$E
obj = expect.$O host.$O ipglob.$O linebuf.$O login.$O main.$O play.$O \ obj = expect.$O fnameat.$O host.$O ipglob.$O linebuf.$O login.$O \
ringbuf.$O secure.$O servcmd.$O termlib.$O version.$O $(LIBOBJS) main.$O play.$O ringbuf.$O secure.$O servcmd.$O termlib.$O version.$O \
$(LIBOBJS)
all: $(prog) all: $(prog)
@ -83,7 +84,7 @@ expect.$O: misc.h proto.h
host.$O: misc.h host.$O: misc.h
linebuf.$O: linebuf.h linebuf.$O: linebuf.h
login.$O: misc.h proto.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 play.$O: linebuf.h misc.h proto.h ringbuf.h secure.h
ringbuf.$O: ringbuf.h ringbuf.$O: ringbuf.h
secure.$O: ringbuf.h secure.h secure.$O: ringbuf.h secure.h

View file

@ -60,6 +60,7 @@ if test "$Windows_API" = yes; then
AC_LIBOBJ([w32/w32io]) AC_LIBOBJ([w32/w32io])
AC_LIBOBJ([w32/w32sockets]) AC_LIBOBJ([w32/w32sockets])
fi fi
MY_WITH_READLINE
### Checks for header files. ### Checks for header files.
@ -97,6 +98,7 @@ AC_OUTPUT
AC_MSG_NOTICE([]) AC_MSG_NOTICE([])
AC_MSG_NOTICE([-= Configuration summary =-]) AC_MSG_NOTICE([-= Configuration summary =-])
AC_MSG_NOTICE([ readline: $with_readline])
AC_MSG_NOTICE([ terminfo: $with_terminfo]) AC_MSG_NOTICE([ terminfo: $with_terminfo])
AC_MSG_NOTICE([ EMPIREHOST: $EMPIREHOST]) AC_MSG_NOTICE([ EMPIREHOST: $EMPIREHOST])
AC_MSG_NOTICE([ EMPIREPORT: $EMPIREPORT]) AC_MSG_NOTICE([ EMPIREPORT: $EMPIREPORT])

View file

@ -30,8 +30,9 @@
* Dave Pare, 1986 * Dave Pare, 1986
* Steve McClure, 1998 * Steve McClure, 1998
* Ron Koenderink, 2004-2007 * Ron Koenderink, 2004-2007
* Markus Armbruster, 2005-2010 * Markus Armbruster, 2005-2015
* Tom Dickson-Hunt, 2010 * Tom Dickson-Hunt, 2010
* Martin Haukeli, 2015
*/ */
#include <config.h> #include <config.h>
@ -40,11 +41,13 @@
#include <string.h> #include <string.h>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <shlobj.h>
#include "sys/socket.h" #include "sys/socket.h"
#else #else
#include <pwd.h> #include <pwd.h>
#endif #endif
#include <unistd.h> #include <unistd.h>
#include "fnameat.h"
#include "misc.h" #include "misc.h"
#include "version.h" #include "version.h"
@ -55,6 +58,7 @@
struct passwd { struct passwd {
char *pw_name; char *pw_name;
char *pw_dir;
}; };
static struct passwd *w32_getpw(void); static struct passwd *w32_getpw(void);
@ -72,6 +76,10 @@ print_usage(char *program_name)
" -r Restricted mode, no redirections\n" " -r Restricted mode, no redirections\n"
" -s [HOST:]PORT Specify server HOST and PORT\n" " -s [HOST:]PORT Specify server HOST and PORT\n"
" -u Use UTF-8\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" " -h display this help and exit\n"
" -v display version information and exit\n", " -v display version information and exit\n",
program_name); program_name);
@ -82,6 +90,7 @@ main(int argc, char **argv)
{ {
int opt; int opt;
char *auxfname = NULL; char *auxfname = NULL;
char *history_file = NULL;
int send_kill = 0; int send_kill = 0;
char *host = NULL; char *host = NULL;
char *port = NULL; char *port = NULL;
@ -90,14 +99,20 @@ main(int argc, char **argv)
char *country; char *country;
char *passwd; char *passwd;
char *uname; char *uname;
char *udir;
char *colon; char *colon;
int sock; int sock;
while ((opt = getopt(argc, argv, "2:krs:uhv")) != EOF) { while ((opt = getopt(argc, argv, "2:H:krs:uhv")) != EOF) {
switch (opt) { switch (opt) {
case '2': case '2':
auxfname = optarg; auxfname = optarg;
break; break;
#ifdef HAVE_LIBREADLINE
case 'H':
history_file = optarg;
break;
#endif /* HAVE_LIBREADLINE */
case 'k': case 'k':
send_kill = 1; send_kill = 1;
break; break;
@ -146,7 +161,8 @@ main(int argc, char **argv)
if (!host) if (!host)
host = empirehost; host = empirehost;
uname = getenv("LOGNAME"); uname = getenv("LOGNAME");
if (uname == NULL) { udir = getenv("HOME");
if (!uname || !udir) {
struct passwd *pwd; struct passwd *pwd;
pwd = getpwuid(getuid()); pwd = getpwuid(getuid());
@ -154,7 +170,10 @@ main(int argc, char **argv)
fprintf(stderr, "You don't exist. Go away\n"); fprintf(stderr, "You don't exist. Go away\n");
exit(1); exit(1);
} }
if (!uname)
uname = pwd->pw_name; uname = pwd->pw_name;
if (!udir)
udir = pwd->pw_dir;
} }
if (*ap) { if (*ap) {
fprintf(stderr, "%s: extra operand %s\n", argv[0], *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); 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)) if (!login(sock, uname, country, passwd, send_kill, utf8))
exit(1); exit(1);
if (play(sock) < 0) if (play(sock, history_file) < 0)
exit(1); exit(1);
return 0; return 0;
@ -183,12 +207,13 @@ main(int argc, char **argv)
#ifdef _WIN32 #ifdef _WIN32
/* /*
* Get Windows user name * Get Windows user name and directory
*/ */
static struct passwd * static struct passwd *
w32_getpw(void) w32_getpw(void)
{ {
static char unamebuf[128]; static char unamebuf[128];
static char udirbuf[MAX_PATH];
static struct passwd pwd; static struct passwd pwd;
DWORD unamesize; DWORD unamesize;
@ -199,6 +224,9 @@ w32_getpw(void)
pwd.pw_name = "nobody"; pwd.pw_name = "nobody";
} else } else
pwd.pw_name = "nobody"; pwd.pw_name = "nobody";
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, udirbuf))
&& strlen(udirbuf) == 0)
pwd.pw_dir = udirbuf;
return &pwd; return &pwd;
} }

View file

@ -28,6 +28,7 @@
* *
* Known contributors to this file: * Known contributors to this file:
* Steve McClure, 1998 * Steve McClure, 1998
* Markus Armbruster, 2004-2017
*/ */
#ifndef MISC_H #ifndef MISC_H
@ -41,8 +42,6 @@
extern char empirehost[]; extern char empirehost[];
extern char empireport[]; extern char empireport[];
extern int eight_bit_clean; extern int eight_bit_clean;
extern int input_fd;
extern int send_eof;
extern FILE *auxfp; extern FILE *auxfp;
extern int restricted; extern int restricted;
@ -61,9 +60,10 @@ int parseid(char *);
int expect(int s, int match, char *buf); int expect(int s, int match, char *buf);
int tcp_connect(char *, char *); int tcp_connect(char *, char *);
int login(int s, char *uname, char *cname, char *cpass, int kill_proc, int); 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 sendcmd(int s, char *cmd, char *arg);
void servercmd(int, char *, int); int servercmd(int, char *, int);
void outch(char); void outch(char);
#ifdef _MSC_VER #ifdef _MSC_VER

View file

@ -27,8 +27,9 @@
* play.c: Playing the game * play.c: Playing the game
* *
* Known contributors to this file: * Known contributors to this file:
* Markus Armbruster, 2007-2010 * Markus Armbruster, 2007-2017
* Ron Koenderink, 2007-2009 * Ron Koenderink, 2007-2009
* Martin Haukeli, 2015
*/ */
#include <config.h> #include <config.h>
@ -51,6 +52,24 @@
#include "ringbuf.h" #include "ringbuf.h"
#include "secure.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 #ifdef _WIN32
static CRITICAL_SECTION signal_critical_section; static CRITICAL_SECTION signal_critical_section;
static LPCRITICAL_SECTION signal_critical_section_ptr = NULL; 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) #define sysdep_stdin_init() ((void)0)
#endif #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. * Receive and process server output from @sock.
* Return number of characters received on success, -1 on error. * Return number of characters received on success, -1 on error.
@ -335,7 +347,7 @@ recv_output(int sock)
static struct lbuf lbuf; static struct lbuf lbuf;
char buf[4096]; char buf[4096];
ssize_t n; ssize_t n;
int i, ch, len; int i, ch, len, fd;
char *line; char *line;
n = read(sock, buf, sizeof(buf)); n = read(sock, buf, sizeof(buf));
@ -381,7 +393,18 @@ recv_output(int sock)
len = lbuf_putc(&lbuf, ch); len = lbuf_putc(&lbuf, ch);
if (len) { if (len) {
line = lbuf_line(&lbuf); 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); lbuf_init(&lbuf);
state = SCANNING_ID; state = SCANNING_ID;
} }
@ -397,28 +420,73 @@ recv_output(int sock)
return n; 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. * Return 1 on receipt of input, zero on EOF, -1 on error.
*/ */
static int static int
recv_input(int fd, struct ring *inbuf) recv_input(int fd, struct ring *inbuf)
{ {
static struct lbuf cmdbuf; int n;
int n, i, ch;
char *line;
int res = 1; 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); n = ring_from_file(inbuf, fd);
if (n < 0) if (n < 0)
return -1; return -1;
if (n == 0) { 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. * Can't put EOF cookie into INBUF here, it may not fit.
* Leave it to caller. * Leave it to caller.
@ -426,19 +494,36 @@ recv_input(int fd, struct ring *inbuf)
res = 0; res = 0;
} }
/* copy input to AUXFP etc. */ return res;
for (i = -n; i < 0; i++) { }
ch = ring_peek(inbuf, i);
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); assert(ch != EOF);
if (ch != '\r' && lbuf_putc(&cmdbuf, ch) > 0) { if (ch != '\r')
line = lbuf_line(&cmdbuf); save_input(ch);
save_input(line);
lbuf_init(&cmdbuf);
}
if (auxfp) if (auxfp)
putc(ch, 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; return res;
} }
@ -450,11 +535,12 @@ intr(int sig)
/* /*
* Play on @sock. * Play on @sock.
* @history_file is the name of the history file, or null.
* The session must be in the playing phase. * The session must be in the playing phase.
* Return 0 when the session ended, -1 on error. * Return 0 when the session ended, -1 on error.
*/ */
int int
play(int sock) play(int sock, char *history_file)
{ {
/* /*
* Player input flows from INPUT_FD through recv_input() into ring * 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 */ struct ring inbuf; /* input buffer, draining to SOCK */
int eof_fd0; /* read fd 0 hit EOF? */ int eof_fd0; /* read fd 0 hit EOF? */
int partial_line_sent; /* partial input line sent? */ int partial_line_sent; /* partial input line sent? */
int send_eof; /* need to send EOF_COOKIE */
fd_set rdfd, wrfd; fd_set rdfd, wrfd;
int n; int n;
int ret = -1;
sa.sa_flags = 0; sa.sa_flags = 0;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@ -475,6 +563,17 @@ play(int sock)
sigaction(SIGINT, &sa, NULL); sigaction(SIGINT, &sa, NULL);
sa.sa_handler = SIG_IGN; sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL); 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); ring_init(&inbuf);
eof_fd0 = partial_line_sent = send_eof = send_intr = 0; 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 * 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. * 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); FD_SET(input_fd, &rdfd);
/* Want to send player input only when we have something */ /* Want to send player input only when we have something */
if (send_intr || send_eof || ring_len(&inbuf)) if (send_intr || send_eof || ring_len(&inbuf))
@ -502,7 +602,7 @@ play(int sock)
if (n < 0) { if (n < 0) {
if (errno != EINTR) { if (errno != EINTR) {
perror("select"); perror("select");
return -1; break;
} }
} }
@ -511,51 +611,52 @@ play(int sock)
partial_line_sent = 0; partial_line_sent = 0;
if (send_eof && !partial_line_sent if (send_eof && !partial_line_sent
&& ring_putm(&inbuf, EOF_COOKIE, sizeof(EOF_COOKIE) - 1) >= 0) && ring_putm(&inbuf, EOF_COOKIE, sizeof(EOF_COOKIE) - 1) >= 0)
send_eof--; send_eof = 0;
if (send_intr && !partial_line_sent if (send_intr && !partial_line_sent
&& ring_putm(&inbuf, INTR_COOKIE, sizeof(INTR_COOKIE) - 1) >= 0) { && ring_putm(&inbuf, INTR_COOKIE, sizeof(INTR_COOKIE) - 1) >= 0) {
send_intr = 0; send_intr = 0;
if (input_fd) { if (input_fd) {
/* execute aborted, switch back to fd 0 */ /* execute aborted, switch back to fd 0 */
close(input_fd); close(input_fd);
input_fd = eof_fd0 ? -1 : 0; input_fd = 0;
} }
} }
if (n < 0) if (n < 0)
continue; continue;
/* read player input */ /* 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); n = recv_input(input_fd, &inbuf);
if (n < 0) { if (n <= 0) {
perror("read stdin"); /* FIXME stdin misleading, could be execing */
n = 0;
}
if (n == 0) {
/* EOF on input */
send_eof++;
if (input_fd) { if (input_fd) {
/* execute done, switch back to fd 0 */ /* execute done, switch back to fd 0 */
if (n < 0) {
perror("read batch file");
send_intr = 1;
} else
send_eof = 1;
close(input_fd); close(input_fd);
input_fd = eof_fd0 ? -1 : 0; input_fd = 0;
} else { } else {
/* stop reading input, drain socket ring buffers */ /* stop reading input, drain socket ring buffers */
if (n < 0)
perror("read stdin");
send_eof = 1;
eof_fd0 = 1; eof_fd0 = 1;
input_fd = -1;
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
sigaction(SIGINT, &sa, NULL); sigaction(SIGINT, &sa, NULL);
send_intr = 0;
} }
} else } else if (ring_len(&inbuf) > 0)
partial_line_sent = ring_peek(&inbuf, -1) != '\n'; partial_line_sent = ring_peek(&inbuf, -1) != '\n';
} }
/* send it to the server */ /* send it to the server */
if (FD_ISSET(sock, &wrfd)) { if (FD_ISSET(sock, &wrfd)) {
n = ring_to_file(&inbuf, sock); n = send_input(sock, &inbuf);
if (n < 0) { if (n < 0) {
perror("write socket"); perror("write socket");
return -1; break;
} }
} }
@ -564,10 +665,43 @@ play(int sock)
n = recv_output(sock); n = recv_output(sock);
if (n < 0) { if (n < 0) {
perror("read socket"); perror("read socket");
return -1; break;
} }
if (n == 0) if (n == 0) {
return 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);
}
} }

View file

@ -27,7 +27,7 @@
* ringbuf.c: Simple ring buffer * ringbuf.c: Simple ring buffer
* *
* Known contributors to this file: * Known contributors to this file:
* Markus Armbruster, 2007-2009 * Markus Armbruster, 2007-2017
*/ */
#include <config.h> #include <config.h>
@ -35,7 +35,6 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/uio.h>
#include "ringbuf.h" #include "ringbuf.h"
/* /*
@ -82,9 +81,17 @@ ring_peek(struct ring *r, int n)
assert(-RING_SIZE - 1 <= n && n <= RING_SIZE); assert(-RING_SIZE - 1 <= n && n <= RING_SIZE);
idx = n >= 0 ? r->cons + n : r->prod - -n; if (n >= 0) {
if (idx < r->cons && idx >= r->prod) idx = r->cons + n;
if (idx >= r->prod)
return EOF; 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]; 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. * Search the ring buffer for zero-terminated string S.
* If found, return a non-negative value referring to the beginning of * Start at the @(n+1)-th byte to be gotten.
* S in the buffer when passed to ring_peek(). Else return -1. * If found, return the number of bytes in the buffer before S.
* Else return -1.
*/ */
int int
ring_search(struct ring *r, char *s) ring_search(struct ring *r, char *s, int n)
{ {
size_t len = strlen(s); size_t len = strlen(s);
size_t i, j; 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++) for (j = 0; s[j] && s[j] == (char)r->buf[(i + j) % RING_SIZE]; j++)
; ;
if (!s[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. * Set up @iov[] to describe complete contents of ring buffer.
* If ring buffer is already empty, do nothing and return 0. * @iov[] must have at least two elements.
* Else attempt to write complete contents with writev(), and return * Return number of elements used (zero for an empty ring buffer).
* its value.
*/ */
int 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 cons = r->cons % RING_SIZE;
unsigned prod = r->prod % RING_SIZE; unsigned prod = r->prod % RING_SIZE;
struct iovec iov[2];
int cnt;
ssize_t res;
if (r->cons == r->prod) if (r->cons == r->prod)
return 0; return 0;
iov[0].iov_base = r->buf + cons; 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..] */ /* r->buf[cons..] */
iov[0].iov_len = RING_SIZE - cons; iov[0].iov_len = RING_SIZE - cons;
/* r->buf[..prod-1] */ /* r->buf[..prod-1] */
iov[1].iov_base = r->buf; iov[1].iov_base = r->buf;
iov[1].iov_len = prod; iov[1].iov_len = prod;
cnt = 2; return 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;
} }

View file

@ -27,13 +27,14 @@
* ringbuf.h: Simple ring buffer * ringbuf.h: Simple ring buffer
* *
* Known contributors to this file: * Known contributors to this file:
* Markus Armbruster, 2007 * Markus Armbruster, 2007-2017
*/ */
#ifndef RINGBUF_H #ifndef RINGBUF_H
#define RINGBUF_H #define RINGBUF_H
#include <stddef.h> #include <stddef.h>
#include <sys/uio.h>
#define RING_SIZE 4096 #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_putc(struct ring *, unsigned char);
extern int ring_putm(struct ring *, void *, size_t); extern int ring_putm(struct ring *, void *, size_t);
extern void ring_discard(struct ring *, int); 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_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 #endif

View file

@ -27,79 +27,81 @@
* secure.c: Check redir etc. to protect against tampering deity * secure.c: Check redir etc. to protect against tampering deity
* *
* Known contributors to this file: * Known contributors to this file:
* Markus Armbruster, 2007 * Markus Armbruster, 2007-2017
*/ */
#include <config.h> #include <config.h>
#include <assert.h> #include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include "ringbuf.h" #include "ringbuf.h"
#include "secure.h" #include "secure.h"
static struct ring recent_input; static struct ring recent_input;
static size_t saved_bytes;
/* /*
* Remember line of input @inp for a while. * Remember 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.
*/ */
size_t void
save_input(char *inp) save_input(char inp)
{ {
size_t len = strlen(inp);
int eol; int eol;
assert(len && inp[len - 1] == '\n'); while (ring_putc(&recent_input, inp) < 0) {
eol = ring_search(&recent_input, "\n", 0);
while (ring_putm(&recent_input, inp, len) < 0) {
eol = ring_search(&recent_input, "\n");
assert(eol >= 0); assert(eol >= 0);
ring_discard(&recent_input, eol + 1); ring_discard(&recent_input, eol + 1);
} }
saved_bytes += len;
return saved_bytes;
} }
/* /*
* Can you still remember a line of input that ends with @tail? * Can you still remember a line of input that ends with @tail?
* It must end with a newline. * 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) seen_input(char *tail)
{ {
size_t len = strlen(tail); size_t len = strlen(tail);
size_t remembered = ring_len(&recent_input);
int dist;
assert(len && tail[len - 1] == '\n'); assert(len && tail[len - 1] == '\n');
return ring_search(&recent_input, tail, 0) >= 0;
dist = ring_search(&recent_input, tail);
if (dist < 0)
return 0;
assert(dist + len <= remembered && remembered <= saved_bytes);
return saved_bytes - remembered + dist + len;
} }
/* /*
* Forget remembered input up to @seen. * Can you still remember input that looks like an execute @arg?
* @seen should be obtained from save_input() or seen_input(). * @arg must end with a newline.
*/ */
void int
forget_input(size_t seen) 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) { n = 1;
assert(ring_peek(&recent_input, seen - forgotten - 1) == '\n'); for (;;) {
ring_discard(&recent_input, seen - forgotten); /* 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;
} }
} }

View file

@ -27,7 +27,7 @@
* secure.h: Check redir etc. to protect against tampering deity * secure.h: Check redir etc. to protect against tampering deity
* *
* Known contributors to this file: * Known contributors to this file:
* Markus Armbruster, 2007-2009 * Markus Armbruster, 2007-2017
*/ */
#ifndef SECURE_H #ifndef SECURE_H
@ -35,8 +35,8 @@
#include <stddef.h> #include <stddef.h>
extern size_t save_input(char *); extern void save_input(char);
extern size_t seen_input(char *); extern int seen_input(char *);
extern void forget_input(size_t); extern int seen_exec_input(char *);
#endif #endif

View file

@ -30,7 +30,7 @@
* Dave Pare, 1989 * Dave Pare, 1989
* Steve McClure, 1998 * Steve McClure, 1998
* Ron Koenderink, 2005 * Ron Koenderink, 2005
* Markus Armbruster, 2005-2010 * Markus Armbruster, 2005-2017
*/ */
#include <config.h> #include <config.h>
@ -41,6 +41,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "misc.h" #include "misc.h"
#include "proto.h" #include "proto.h"
#include "secure.h" #include "secure.h"
@ -52,14 +53,12 @@ int restricted;
static FILE *redir_fp; static FILE *redir_fp;
static int redir_is_pipe; static int redir_is_pipe;
static int executing; static int executing;
static size_t input_to_forget;
static void prompt(int, char *, char *);
static void doredir(char *p); static void doredir(char *p);
static void dopipe(char *p); static void dopipe(char *p);
static int doexecute(char *p); static int doexecute(char *p);
void int
servercmd(int code, char *arg, int len) servercmd(int code, char *arg, int len)
{ {
static int nmin, nbtu, fd; static int nmin, nbtu, fd;
@ -69,7 +68,8 @@ servercmd(int code, char *arg, int len)
switch (code) { switch (code) {
case C_PROMPT: case C_PROMPT:
if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) { 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 : ", snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
nmin, nbtu); nmin, nbtu);
@ -80,10 +80,7 @@ servercmd(int code, char *arg, int len)
(void)fclose(redir_fp); (void)fclose(redir_fp);
redir_fp = NULL; redir_fp = NULL;
} }
if (input_to_forget) { outch('\n');
forget_input(input_to_forget);
input_to_forget = 0;
}
prompt(code, the_prompt, teles); prompt(code, the_prompt, teles);
executing = 0; executing = 0;
break; break;
@ -93,13 +90,9 @@ servercmd(int code, char *arg, int len)
break; break;
case C_EXECUTE: case C_EXECUTE:
fd = doexecute(arg); fd = doexecute(arg);
if (fd < 0) if (fd >= 0)
send_eof++;
else {
input_fd = fd;
executing = 1; executing = 1;
} return fd;
break;
case C_EXIT: case C_EXIT:
printf("Exit: %s", arg); printf("Exit: %s", arg);
if (auxfp) if (auxfp)
@ -114,6 +107,7 @@ servercmd(int code, char *arg, int len)
if (arg[0] != '\n') { if (arg[0] != '\n') {
snprintf(teles, sizeof(teles), "(%.*s) ", len - 1, arg); snprintf(teles, sizeof(teles), "(%.*s) ", len - 1, arg);
if (!redir_fp) { if (!redir_fp) {
outch('\n');
putchar('\07'); putchar('\07');
prompt(code, the_prompt, teles); prompt(code, the_prompt, teles);
} }
@ -130,20 +124,8 @@ servercmd(int code, char *arg, int len)
assert(0); assert(0);
break; break;
} }
}
static void return 0;
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);
}
} }
static char * static char *
@ -158,10 +140,8 @@ fname(char *s)
} }
static int static int
redir_authorized(char *arg, char *attempt, int expected) common_authorized(char *arg, char *attempt)
{ {
size_t seen = seen_input(arg);
if (restricted) { if (restricted) {
fprintf(stderr, "Can't %s in restricted mode\n", attempt); fprintf(stderr, "Can't %s in restricted mode\n", attempt);
return 0; 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); fprintf(stderr, "Can't %s in a batch file\n", attempt);
return 0; return 0;
} }
return 1;
}
if (!expected) { static int
fprintf(stderr, "WARNING! Server attempted to %s unexpectedly\n", redir_authorized(char *arg, char *attempt)
attempt); {
return 0; if (redir_fp) {
} fprintf(stderr, "Warning: dropped conflicting %s %s",
if (!seen || (input_to_forget && input_to_forget != seen)) {
fprintf(stderr, "WARNING! Server attempted to %s %s\n",
attempt, arg); attempt, arg);
return 0; 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 static void
@ -193,10 +190,10 @@ doredir(char *p)
int mode; int mode;
int fd; int fd;
if (!redir_authorized(p, "redirect to file", !redir_fp)) if (!redir_authorized(p, "redirect to file"))
return; return;
if (*p++ != '>') { if (*p++ != '>') {
fprintf(stderr, "WARNING! Weird redirection %s", p); fprintf(stderr, "Warning: dropped weird redirection %s", p);
return; return;
} }
@ -228,10 +225,10 @@ doredir(char *p)
static void static void
dopipe(char *p) dopipe(char *p)
{ {
if (!redir_authorized(p, "pipe to shell command", !redir_fp)) if (!redir_authorized(p, "pipe to shell command"))
return; return;
if (*p++ != '|') { if (*p++ != '|') {
fprintf(stderr, "WARNING! Weird pipe %s", p); fprintf(stderr, "Warning: dropped weird pipe %s", p);
return; return;
} }
@ -241,10 +238,14 @@ dopipe(char *p)
return; return;
} }
/* strip newline */
p[strlen(p) - 1] = 0;
redir_is_pipe = 1; redir_is_pipe = 1;
errno = 0;
if ((redir_fp = popen(p, "w")) == NULL) { if ((redir_fp = popen(p, "w")) == NULL) {
fprintf(stderr, "Can't redirect to pipe %s: %s\n", fprintf(stderr, "Can't redirect to pipe %s%s%s\n",
p, strerror(errno)); p, errno ? ": " : "", errno ? strerror(errno) : "");
} }
} }
@ -253,7 +254,7 @@ doexecute(char *p)
{ {
int fd; int fd;
if (!redir_authorized(p, "execute batch file", 1)) if (!exec_authorized(p))
return -1; return -1;
p = fname(p); p = fname(p);
@ -263,7 +264,7 @@ doexecute(char *p)
} }
if ((fd = open(p, O_RDONLY)) < 0) { 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)); p, strerror(errno));
return -1; return -1;
} }

View file

@ -35,6 +35,7 @@
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include "file.h" #include "file.h"
#include "fnameat.h"
#include "optlist.h" #include "optlist.h"
#include "prototypes.h" #include "prototypes.h"
#include "xdump.h" #include "xdump.h"

View file

@ -50,6 +50,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "fnameat.h"
#include "misc.h" #include "misc.h"
#include "optlist.h" #include "optlist.h"
#include "prototypes.h" #include "prototypes.h"

View file

@ -33,7 +33,9 @@
#include <config.h> #include <config.h>
#include <errno.h> #include <errno.h>
#include "prototypes.h" #include <stdlib.h>
#include <string.h>
#include "fnameat.h"
static int fname_is_abs(const char *); static int fname_is_abs(const char *);