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)
|
$(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 $^ >$@
|
||||||
|
|
|
@ -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
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 */
|
/* 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
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],
|
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
|
||||||
|
|
29
man/empire.6
29
man/empire.6
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
assert(ch != EOF);
|
|
||||||
if (ch != '\r' && lbuf_putc(&cmdbuf, ch) > 0) {
|
|
||||||
line = lbuf_line(&cmdbuf);
|
|
||||||
save_input(line);
|
|
||||||
lbuf_init(&cmdbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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')
|
||||||
|
save_input(ch);
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
|
||||||
fprintf(stderr, "WARNING! Server attempted to %s unexpectedly\n",
|
|
||||||
attempt);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!seen || (input_to_forget && input_to_forget != seen)) {
|
static int
|
||||||
fprintf(stderr, "WARNING! Server attempted to %s %s\n",
|
redir_authorized(char *arg, char *attempt)
|
||||||
|
{
|
||||||
|
if (redir_fp) {
|
||||||
|
fprintf(stderr, "Warning: dropped conflicting %s %s",
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue