summaryrefslogtreecommitdiffstats
path: root/lib/ss
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/ss/Android.bp39
-rw-r--r--lib/ss/Makefile.in234
-rw-r--r--lib/ss/ct_c.awk75
-rw-r--r--lib/ss/ct_c.sed160
-rw-r--r--lib/ss/data.c20
-rw-r--r--lib/ss/error.c77
-rw-r--r--lib/ss/execute_cmd.c229
-rw-r--r--lib/ss/get_readline.c100
-rw-r--r--lib/ss/help.c185
-rw-r--r--lib/ss/invocation.c132
-rw-r--r--lib/ss/list_rqs.c92
-rw-r--r--lib/ss/listen.c200
-rw-r--r--lib/ss/mit-sipb-copyright.h19
-rw-r--r--lib/ss/mk_cmds.159
-rw-r--r--lib/ss/mk_cmds.sh.in56
-rw-r--r--lib/ss/pager.c152
-rw-r--r--lib/ss/parse.c158
-rw-r--r--lib/ss/prompt.c31
-rw-r--r--lib/ss/request_tbl.c68
-rw-r--r--lib/ss/requests.c66
-rw-r--r--lib/ss/ss.h96
-rw-r--r--lib/ss/ss.pc.in12
-rw-r--r--lib/ss/ss_err.et39
-rw-r--r--lib/ss/ss_internal.h107
-rw-r--r--lib/ss/std_rqs.ct46
-rw-r--r--lib/ss/test_cmd.ct6
-rw-r--r--lib/ss/test_script8
-rw-r--r--lib/ss/test_script_expected22
-rw-r--r--lib/ss/test_ss.c151
29 files changed, 2639 insertions, 0 deletions
diff --git a/lib/ss/Android.bp b/lib/ss/Android.bp
new file mode 100644
index 0000000..ebc1e1a
--- /dev/null
+++ b/lib/ss/Android.bp
@@ -0,0 +1,39 @@
+// Copyright 2017 The Android Open Source Project
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "external_e2fsprogs_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-0BSD
+ // SPDX-license-identifier-MIT
+ default_applicable_licenses: ["external_e2fsprogs_license"],
+}
+
+cc_library {
+ name: "libext2_ss",
+ host_supported: true,
+ unique_host_soname: true,
+ defaults: ["e2fsprogs-defaults"],
+ srcs: [
+ "ss_err.c",
+ "std_rqs.c",
+ "invocation.c",
+ "help.c",
+ "execute_cmd.c",
+ "listen.c",
+ "parse.c",
+ "error.c",
+ "prompt.c",
+ "request_tbl.c",
+ "list_rqs.c",
+ "pager.c",
+ "requests.c",
+ "data.c",
+ "get_readline.c",
+ ],
+ shared_libs: ["libext2_com_err"],
+ header_libs: ["libext2-headers"],
+ export_include_dirs: ["."],
+ export_header_lib_headers: ["libext2-headers"],
+}
diff --git a/lib/ss/Makefile.in b/lib/ss/Makefile.in
new file mode 100644
index 0000000..bb50418
--- /dev/null
+++ b/lib/ss/Makefile.in
@@ -0,0 +1,234 @@
+#
+# Makefile for lib/ss
+#
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+top_builddir = ../..
+my_dir = lib/ss
+INSTALL = @INSTALL@
+MKDIR_P = @MKDIR_P@
+DLOPEN_LIB = @DLOPEN_LIB@
+
+@MCONFIG@
+
+LIBRARY= libss
+LIBDIR= ss
+
+ELF_VERSION = 2.0
+ELF_SO_VERSION = 2
+ELF_IMAGE = libss
+ELF_MYDIR = ss
+ELF_INSTALL_DIR = $(root_libdir)
+ELF_OTHER_LIBS = -lcom_err $(DLOPEN_LIB)
+
+BSDLIB_VERSION = 1.0
+BSDLIB_IMAGE = libss
+BSDLIB_MYDIR = ss
+BSDLIB_INSTALL_DIR = $(root_libdir)
+
+TAGS=etags
+MK_CMDS= _SS_DIR_OVERRIDE=$(srcdir) ./mk_cmds
+COMPILE_ET= _ET_DIR_OVERRIDE=$(srcdir)/../et ../et/compile_et
+
+.c.o:
+ $(E) " CC $<"
+ $(Q) $(CC) $(ALL_CFLAGS_STLIB) -c $<
+ $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+ $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
+@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS_STLIB) -g -pg -o profiled/$*.o -c $<
+@ELF_CMT@ $(Q) $(CC) $(ALL_CFLAGS_SHLIB) -DSHARED_ELF_LIB -fPIC -shared -o elfshared/$*.o -c $<
+@BSDLIB_CMT@ $(Q) $(CC) $(ALL_CFLAGS_SHLIB) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
+
+# for the library
+
+# with ss_err.o first, ss_err.h should get rebuilt first too. should not
+# be relying on this, though.
+OBJS= ss_err.o \
+ std_rqs.o \
+ invocation.o help.o \
+ execute_cmd.o listen.o parse.o error.o prompt.o \
+ request_tbl.o list_rqs.o pager.o requests.o \
+ data.o get_readline.o
+
+SRCS= $(srcdir)/invocation.c $(srcdir)/help.c \
+ $(srcdir)/execute_cmd.c $(srcdir)/listen.c $(srcdir)/parse.c \
+ $(srcdir)/error.c $(srcdir)/prompt.c $(srcdir)/request_tbl.c \
+ $(srcdir)/list_rqs.c $(srcdir)/pager.c $(srcdir)/requests.c \
+ $(srcdir)/data.c $(srcdir)/get_readline.c
+
+all:: mk_cmds
+
+@MAKEFILE_LIBRARY@
+@MAKEFILE_ELF@
+@MAKEFILE_BSDLIB@
+@MAKEFILE_PROFILE@
+
+CODE= $(SRCS) $(MKCMDSFILES)
+
+MKCMDSOBJS= mk_cmds.o utils.o options.o ct.tab.o cmd_tbl.lex.o
+
+MKCMDSFILES= mk_cmds.c utils.c options.c ct.y cmd_tbl.lex.l
+
+MKCMDSCSRCS= mk_cmds.c utils.c options.c ct.tab.c cmd_tbl.lex.c
+
+
+HFILES= ss.h ss_internal.h
+SHARE_FILES= ct_c.awk ct_c.sed
+
+INSTALL_HFILES= ss.h
+
+# for 'tags' and dependencies
+
+CFILES= $(SRCS) $(MKCMDSCSRCS) test_ss.c
+
+# for building archives
+
+FILES= $(SRCS) $(MKCMDSFILES) $(HFILES) \
+ ss_err.et std_rqs.ct Makefile \
+ test_ss.c ss
+
+all:: libss.a ss.pc # libss_p.a lint
+
+std_rqs.c: std_rqs.ct mk_cmds
+ $(E) " MK_CMDS $@"
+ $(Q) DIR=$(srcdir) $(MK_CMDS) $(srcdir)/std_rqs.ct
+
+std_rqs.o: ss_err.h
+
+test_cmd.c: test_cmd.ct mk_cmds
+ $(E) " MK_CMDS $@"
+ $(Q) DIR=$(srcdir) $(MK_CMDS) $(srcdir)/test_cmd.ct
+
+ss_err.c ss_err.h: ss_err.et
+ $(E) " COMPILE_ET ss_err.et"
+ $(Q) $(COMPILE_ET) $(srcdir)/ss_err.et
+
+ct.tab.c ct.tab.h: ct.y
+ $(RM) -f ct.tab.* y.*
+ $(YACC) -d $(srcdir)/ct.y
+ $(MV) -f y.tab.c ct.tab.c
+ $(MV) -f y.tab.h ct.tab.h
+
+#libss.o: $(OBJS)
+# $(LD) -r -s -o $@ $(OBJS)
+# $(CHMOD) -x $@
+
+mk_cmds: $(DEP_SUBSTITUTE) $(srcdir)/mk_cmds.sh.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE) $(srcdir)/mk_cmds.sh.in mk_cmds
+ $(Q) $(CHMOD) +x mk_cmds
+
+ss.pc: $(srcdir)/ss.pc.in $(top_builddir)/config.status
+ $(E) " CONFIG.STATUS $@"
+ $(Q) cd $(top_builddir); CONFIG_FILES=lib/ss/ss.pc ./config.status
+
+installdirs::
+ $(E) " MKDIR_P $(libdir) $(includedir)/ss $(datadir)/ss $(bindir) $(pkgconfigdir) $(man1dir)"
+ $(Q) $(MKDIR_P) $(DESTDIR)$(libdir) \
+ $(DESTDIR)$(includedir)/ss $(DESTDIR)$(datadir)/ss \
+ $(DESTDIR)$(bindir) $(DESTDIR)$(pkgconfigdir) \
+ $(DESTDIR)$(man1dir)
+
+install:: libss.a $(INSTALL_HFILES) installdirs ss_err.h mk_cmds ss.pc
+ $(E) " INSTALL_DATA $(DESTDIR)$(libdir)/libss.a"
+ $(Q) $(INSTALL_DATA) libss.a $(DESTDIR)$(libdir)/libss.a
+ -$(Q) $(RANLIB) $(DESTDIR)$(libdir)/libss.a
+ $(Q) $(CHMOD) $(LIBMODE) $(DESTDIR)$(libdir)/libss.a
+ $(Q) $(RM) -f $(DESTDIR)$(includedir)/ss/*
+ $(Q) for i in $(INSTALL_HFILES); do \
+ echo " INSTALL_DATA $(DESTDIR)$(includedir)/ss/$$i"; \
+ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir)/ss/$$i; \
+ done
+ $(E) " INSTALL_DATA $(includedir)/ss/ss_err.h"
+ $(Q) $(INSTALL_DATA) ss_err.h $(DESTDIR)$(includedir)/ss/ss_err.h
+ $(Q) for i in $(SHARE_FILES); do \
+ echo " INSTALL_DATA $(DESTDIR)$(datadir)/ss/$$i"; \
+ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(datadir)/ss/$$i; \
+ done
+ $(E) " INSTALL $(bindir)/mk_cmds"
+ $(Q) $(INSTALL) mk_cmds $(DESTDIR)$(bindir)/mk_cmds
+ $(E) " INSTALL_DATA $(man1dir)/mk_cmds.1"
+ $(Q) $(INSTALL_DATA) $(srcdir)/mk_cmds.1 $(DESTDIR)$(man1dir)/mk_cmds.1
+ $(E) " INSTALL_DATA $(pkgconfigdir)/ss.pc"
+ $(Q) $(INSTALL_DATA) ss.pc $(DESTDIR)$(pkgconfigdir)/ss.pc
+
+uninstall::
+ $(RM) -f $(DESTDIR)$(libdir)/libss.a $(DESTDIR)$(bindir)/mk_cmds \
+ $(DESTDIR)$(pkgconfigdir)/ss.pc \
+ $(DESTDIR)$(man1dir)/mk_cmds.1
+ $(RM) -rf $(DESTDIR)$(includedir)/ss $(DESTDIR)$(datadir)/ss
+
+test_ss: test_ss.o test_cmd.o $(DEPLIBSS) $(DEPLIBCOM_ERR)
+ $(E) " LD $@"
+ $(Q) $(CC) -o $@ test_ss.o test_cmd.o $(ALL_CFLAGS) $(ALL_LDFLAGS) \
+ $(LIBSS) $(LIBCOM_ERR) $(SYSLIBS)
+
+fullcheck check:: all test_ss
+ $(E) " RUN TEST test_ss"
+ -@($(TESTENV) ./test_ss -f $(srcdir)/test_script > test_out 2>&1; exit 0)
+ $(Q) if diff test_out $(srcdir)/test_script_expected > test.diff; then \
+ true ; else echo "Regression test for ss library failed!"; exit 1 ; fi
+
+clean::
+ $(RM) -f ../libss.a libss.a mk_cmds ss_err.h ss_err.c std_rqs.c \
+ tst_cmds.c test_ss test_out test.diff *.o *~ \#* *.bak core \
+ test_cmd.c ss.pc
+
+mostlyclean:: clean
+distclean:: clean
+ $(RM) -f .depend Makefile ss.pc \
+ $(srcdir)/TAGS $(srcdir)/Makefile.in.old
+
+#
+# Hack to parallel makes recognize dependencies correctly.
+#
+$(top_builddir)/lib/ss/ss_err.h: ss_err.h
+
+$(OBJS): subdirs
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+invocation.o: $(srcdir)/invocation.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+help.o: $(srcdir)/help.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+execute_cmd.o: $(srcdir)/execute_cmd.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+listen.o: $(srcdir)/listen.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+parse.o: $(srcdir)/parse.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+error.o: $(srcdir)/error.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ss_internal.h $(srcdir)/ss.h $(top_builddir)/lib/ss/ss_err.h
+prompt.o: $(srcdir)/prompt.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+request_tbl.o: $(srcdir)/request_tbl.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+list_rqs.o: $(srcdir)/list_rqs.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+pager.o: $(srcdir)/pager.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+requests.o: $(srcdir)/requests.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+data.o: $(srcdir)/data.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
+get_readline.o: $(srcdir)/get_readline.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ss_internal.h $(srcdir)/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
diff --git a/lib/ss/ct_c.awk b/lib/ss/ct_c.awk
new file mode 100644
index 0000000..a4424c8
--- /dev/null
+++ b/lib/ss/ct_c.awk
@@ -0,0 +1,75 @@
+/^command_table / {
+ cmdtbl = $2;
+ printf "/* %s.c - automatically generated from %s.ct */\n", \
+ rootname, rootname > outfile
+ print "#include <ss/ss.h>" > outfile
+ print "" >outfile
+}
+
+/^BOR$/ {
+ cmdnum++
+ options = 0
+ cmdtab = ""
+ printf "static char const * const ssu%05d[] = {\n", cmdnum > outfile
+}
+
+/^sub/ {
+ subr = substr($0, 6, length($0)-5)
+}
+
+/^hlp/ {
+ help = substr($0, 6, length($0)-5)
+}
+
+/^cmd/ {
+ cmd = substr($0, 6, length($0)-5)
+ printf "%s\"%s\",\n", cmdtab, cmd > outfile
+ cmdtab = " "
+}
+
+/^opt/ {
+ opt = substr($0, 6, length($0)-5)
+ if (opt == "dont_list") {
+ options += 1
+ }
+ if (opt == "dont_summarize") {
+ options += 2
+ }
+}
+
+/^EOR/ {
+ print " (char const *)0" > outfile
+ print "};" > outfile
+ printf "extern void %s __SS_PROTO;\n", subr > outfile
+ # Work around a bug in gawk 3.0.5
+ awk_bug = cmdnum
+ subr_tab[awk_bug] = subr
+ options_tab[awk_bug] = options
+ help_tab[awk_bug] = help
+}
+
+/^[0-9]/ {
+ linenum = $1;
+}
+
+/^ERROR/ {
+ error = substr($0, 8, length($0)-7)
+ printf "Error in line %d: %s\n", linenum, error
+ print "#__ERROR_IN_FILE__" > outfile
+}
+
+END {
+ printf "static ss_request_entry ssu%05d[] = {\n", cmdnum+1 > outfile
+ for (i=1; i <= cmdnum; i++) {
+ printf " { ssu%05d,\n", i > outfile
+ printf " %s,\n", subr_tab[i] > outfile
+ printf " \"%s\",\n", help_tab[i] > outfile
+ printf " %d },\n", options_tab[i] > outfile
+ }
+ print " { 0, 0, 0, 0 }" > outfile
+ print "};" > outfile
+ print "" > outfile
+ printf "ss_request_table %s = { 2, ssu%05d };\n", \
+ cmdtbl, cmdnum+1 > outfile
+}
+
diff --git a/lib/ss/ct_c.sed b/lib/ss/ct_c.sed
new file mode 100644
index 0000000..9e5eebb
--- /dev/null
+++ b/lib/ss/ct_c.sed
@@ -0,0 +1,160 @@
+#
+# This script parses a command_table file into something which is a bit
+# easier for an awk script to understand.
+#
+# Input syntax: a .ct file
+#
+# Output syntax:
+# (for the command_table line)
+# command_table <command_table>
+#
+#(for each request definition)
+# BOR
+# sub: <subroutine name>
+# hlp: <help text>
+# cmd: <command>
+# opt: <option>
+# EOR
+# (there may be more than one 'cmd' or 'opt' line
+#
+# A number sent to the output represents a parse error --- it will be
+# followed by the next line which will have the form:
+# ERROR: <error text>
+#
+# The design of this output syntax is such that it should be easy for
+# an awk script to parse.
+
+#
+# The first section of this script is just to canonicalize the file.
+# It removes comments, and puts each command_table request onto a single
+# line
+#
+:FIRST
+y/ / /
+s/^ *//
+s/#.*$//
+/; *$/!{
+N
+y/ / /
+s/\n */ /
+bFIRST
+}
+s/, */, /g
+#
+# Now we take care of some syntactic sugar.....
+#
+/^unimplemented/ {
+ s/^unimplemented [A-Za-z_0-9]*/request ss_unimplemented/
+ s/;/, (dont_list, dont_summarize);/
+}
+/^unknown/ {
+ s/^unknown /request ss_unknown, "", /
+}
+#
+# Dispatch based on the keyword.... illegal keywords are prefixed by ERROR:
+# and are handled by the awk script.
+#
+/^command_table /bCMD
+/^request /bREQUEST
+/^end;/bEND
+s/ .*//
+s/^/ERROR: unknown keyword: /
+=
+b
+#
+# Handle the command_table keyword
+#
+:CMD
+s/;$//
+p
+d
+b
+#
+# Handle the request keyword --- this is the heart of the sed script.
+#
+:REQUEST
+s/^request *//
+h
+i\
+BOR
+# First, parse out the subroutine name
+s/^/sub: /
+s/,.*//
+p
+# Next, parse out the help message, being careful to handle a quoted string
+g
+s/^[^,]*, *//
+h
+/^"/ {
+ s/^"//
+ s/".*//
+ x
+ s/^"[^"]*", *//
+ x
+ b EMITHLP
+}
+s/[^a-zA-Z0-9].*//
+x
+s/[a-zA-Z0-9]*, *//
+x
+:EMITHLP
+s/^/hlp: /
+p
+# Next take care of the command names
+:CMDLIST
+g
+/^(/b OPTIONS
+/^;/b EOR
+/^"/ {
+ s/^"//
+ s/".*//
+ x
+ s/^"[^"]*"//
+ s/, *//
+ x
+ b EMITREQ
+}
+s/[^A-Za-z_0-9].*//
+x
+s/[A-Za-z_0-9]*//
+s/, *//
+x
+:EMITREQ
+s/^/cmd: /
+p
+b CMDLIST
+#
+# Here we parse the list of options.
+#
+: OPTIONS
+g
+s/^(//
+h
+: OPTLIST
+/^)/ b EOR
+/^[^A-Za-z_0-9]/ {
+ =
+ c\
+ERROR: parse error in options list
+}
+s/[^A-Za-z_0-9].*//
+x
+s/[A-Za-z_0-9]*//
+s/, *//
+x
+s/^/opt: /
+p
+g
+b OPTLIST
+: EOR
+c\
+EOR\
+
+d
+b
+#
+# Handle the end keyword --- it's basically ignored.
+#
+:END
+d
+b
diff --git a/lib/ss/data.c b/lib/ss/data.c
new file mode 100644
index 0000000..e8245bd
--- /dev/null
+++ b/lib/ss/data.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright 1987, 1988, 1989 Massachusetts Institute of Technology
+ * (Student Information Processing Board)
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include "ss_internal.h"
+
+ss_data **_ss_table = (ss_data **)NULL;
+char *_ss_pager_name = (char *)NULL;
diff --git a/lib/ss/error.c b/lib/ss/error.c
new file mode 100644
index 0000000..656b71b
--- /dev/null
+++ b/lib/ss/error.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1987, 1988, 1989 by MIT Student Information Processing
+ * Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include "et/com_err.h"
+#include "ss_internal.h"
+
+#include <stdarg.h>
+
+char *ss_name(int sci_idx)
+{
+ register char *ret_val;
+ register ss_data *infop;
+
+ infop = ss_info(sci_idx);
+ if (infop->current_request == (char const *)NULL) {
+ ret_val = malloc((unsigned)
+ (strlen(infop->subsystem_name)+1)
+ * sizeof(char));
+ if (ret_val == (char *)NULL)
+ return((char *)NULL);
+ strcpy(ret_val, infop->subsystem_name);
+ return(ret_val);
+ }
+ else {
+ register char *cp;
+ register char const *cp1;
+ ret_val = malloc((unsigned)sizeof(char) *
+ (strlen(infop->subsystem_name)+
+ strlen(infop->current_request)+
+ 4));
+ if (ret_val == (char *)NULL)
+ return ((char *)NULL);
+ cp = ret_val;
+ cp1 = infop->subsystem_name;
+ while (*cp1)
+ *cp++ = *cp1++;
+ *cp++ = ' ';
+ *cp++ = '(';
+ cp1 = infop->current_request;
+ while (*cp1)
+ *cp++ = *cp1++;
+ *cp++ = ')';
+ *cp = '\0';
+ return(ret_val);
+ }
+}
+
+void ss_error (int sci_idx, long code, const char * fmt, ...)
+{
+ register char *whoami;
+ va_list pvar;
+
+ va_start (pvar, fmt);
+ whoami = ss_name (sci_idx);
+ com_err_va (whoami, code, fmt, pvar);
+ free (whoami);
+ va_end(pvar);
+}
+
+void ss_perror(int sci_idx, long code, char const *msg) /* for compatibility */
+{
+ ss_error (sci_idx, code, "%s", msg);
+}
diff --git a/lib/ss/execute_cmd.c b/lib/ss/execute_cmd.c
new file mode 100644
index 0000000..d092134
--- /dev/null
+++ b/lib/ss/execute_cmd.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright 1987, 1988, 1989 by Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#ifdef HAS_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "ss_internal.h"
+#include <stdio.h>
+
+static int check_request_table PROTOTYPE((ss_request_table *rqtbl, int argc,
+ char *argv[], int sci_idx));
+static int really_execute_command PROTOTYPE((int sci_idx, int argc,
+ char **argv[]));
+
+/*
+ * get_request(tbl, idx)
+ *
+ * Function:
+ * Gets the idx'th request from the request table pointed to
+ * by tbl.
+ * Arguments:
+ * tbl (ss_request_table *)
+ * pointer to request table
+ * idx (int)
+ * index into table
+ * Returns:
+ * (ss_request_entry *)
+ * pointer to request table entry
+ * Notes:
+ * Has been replaced by a macro.
+ */
+
+#ifdef __SABER__
+/* sigh. saber won't deal with pointer-to-const-struct */
+static struct _ss_request_entry * get_request (tbl, idx)
+ ss_request_table * tbl;
+ int idx;
+{
+ struct _ss_request_table *tbl1 = (struct _ss_request_table *) tbl;
+ struct _ss_request_entry *e = (struct _ss_request_entry *) tbl1->requests;
+ return e + idx;
+}
+#else
+#define get_request(tbl,idx) ((tbl) -> requests + (idx))
+#endif
+
+/*
+ * check_request_table(rqtbl, argc, argv, sci_idx)
+ *
+ * Function:
+ * If the command string in argv[0] is in the request table, execute
+ * the commands and return error code 0. Otherwise, return error
+ * code ss_et_command_not_found.
+ * Arguments:
+ * rqtbl (ss_request_table *)
+ * pointer to request table
+ * argc (int)
+ * number of elements in argv[]
+ * argv (char *[])
+ * argument string array
+ * sci_idx (int)
+ * ss-internal index for subsystem control info structure
+ * Returns:
+ * (int)
+ * zero if command found, ss_et_command_not_found otherwise
+ * Notes:
+ */
+
+static int check_request_table(register ss_request_table *rqtbl, int argc,
+ char *argv[], int sci_idx)
+{
+#ifdef __SABER__
+ struct _ss_request_entry *request;
+#else
+ register ss_request_entry *request;
+#endif
+ register ss_data *info;
+ register char const * const * name;
+ char *string = argv[0];
+ int i;
+
+ info = ss_info(sci_idx);
+ info->argc = argc;
+ info->argv = argv;
+ for (i = 0; (request = get_request(rqtbl, i))->command_names; i++) {
+ for (name = request->command_names; *name; name++)
+ if (!strcmp(*name, string)) {
+ info->current_request = request->command_names[0];
+ (request->function)(argc, (const char *const *) argv,
+ sci_idx,info->info_ptr);
+ info->current_request = (char *)NULL;
+ return(0);
+ }
+ }
+ return(SS_ET_COMMAND_NOT_FOUND);
+}
+
+/*
+ * really_execute_command(sci_idx, argc, argv)
+ *
+ * Function:
+ * Fills in the argc, argv values in the subsystem entry and
+ * call the appropriate routine.
+ * Arguments:
+ * sci_idx (int)
+ * ss-internal index for subsystem control info structure
+ * argc (int)
+ * number of arguments in argument list
+ * argv (char **[])
+ * pointer to parsed argument list (may be reallocated
+ * on abbrev expansion)
+ *
+ * Returns:
+ * (int)
+ * Zero if successful, ss_et_command_not_found otherwise.
+ * Notes:
+ */
+
+static int really_execute_command(int sci_idx, int argc, char **argv[])
+{
+ register ss_request_table **rqtbl;
+ register ss_data *info;
+
+ info = ss_info(sci_idx);
+
+ for (rqtbl = info->rqt_tables; *rqtbl; rqtbl++) {
+ if (check_request_table (*rqtbl, argc, *argv, sci_idx) == 0)
+ return(0);
+ }
+ return(SS_ET_COMMAND_NOT_FOUND);
+}
+
+/*
+ * ss_execute_command(sci_idx, argv)
+ *
+ * Function:
+ * Executes a parsed command list within the subsystem.
+ * Arguments:
+ * sci_idx (int)
+ * ss-internal index for subsystem control info structure
+ * argv (char *[])
+ * parsed argument list
+ * Returns:
+ * (int)
+ * Zero if successful, ss_et_command_not_found otherwise.
+ * Notes:
+ */
+
+int ss_execute_command(int sci_idx, register char *argv[])
+{
+ register int i, argc;
+ char **argp;
+
+ argc = 0;
+ for (argp = argv; *argp; argp++)
+ argc++;
+ argp = (char **)malloc((argc+1)*sizeof(char *));
+ if (!argp)
+ return(ENOMEM);
+ for (i = 0; i <= argc; i++)
+ argp[i] = argv[i];
+ i = really_execute_command(sci_idx, argc, &argp);
+ free(argp);
+ return(i);
+}
+
+/*
+ * ss_execute_line(sci_idx, line_ptr)
+ *
+ * Function:
+ * Parses and executes a command line within a subsystem.
+ * Arguments:
+ * sci_idx (int)
+ * ss-internal index for subsystem control info structure
+ * line_ptr (char *)
+ * Pointer to command line to be parsed.
+ * Returns:
+ * (int)
+ * Error code.
+ * Notes:
+ */
+
+int ss_execute_line(int sci_idx, char *line_ptr)
+{
+ char **argv;
+ int argc, ret;
+
+ /* flush leading whitespace */
+ while (line_ptr[0] == ' ' || line_ptr[0] == '\t')
+ line_ptr++;
+
+ /* check if it should be sent to operating system for execution */
+ if (*line_ptr == '!') {
+ if (ss_info(sci_idx)->flags.escape_disabled)
+ return SS_ET_ESCAPE_DISABLED;
+ else {
+ line_ptr++;
+ return (system(line_ptr) < 0) ? errno : 0;
+ }
+ }
+
+ /* parse it */
+ argv = ss_parse(sci_idx, line_ptr, &argc);
+ if (argc == 0) {
+ free(argv);
+ return 0;
+ }
+
+ /* look it up in the request tables, execute if found */
+ ret = really_execute_command (sci_idx, argc, &argv);
+
+ free(argv);
+
+ return(ret);
+}
diff --git a/lib/ss/get_readline.c b/lib/ss/get_readline.c
new file mode 100644
index 0000000..aa16157
--- /dev/null
+++ b/lib/ss/get_readline.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2003 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#ifdef HAS_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "ss_internal.h"
+#define size sizeof(ss_data *)
+#ifdef HAVE_DLOPEN
+#include <dlfcn.h>
+#endif
+
+#ifdef HAVE_DLOPEN
+static void ss_release_readline(ss_data *info)
+{
+ if (!info->readline_handle)
+ return;
+
+ info->readline = 0;
+ info->add_history = 0;
+ info->redisplay = 0;
+ info->rl_completion_matches = 0;
+ dlclose(info->readline_handle);
+ info->readline_handle = 0;
+}
+#endif
+
+/* Libraries we will try to use for readline/editline functionality */
+#define DEFAULT_LIBPATH "libreadline.so.8:libreadline.so.7:libreadline.so.6:libreadline.so.5:libreadline.so.4:libreadline.so:libedit.so.2:libedit.so:libeditline.so.0:libeditline.so"
+
+#ifdef HAVE_DLOPEN
+void ss_get_readline(int sci_idx)
+{
+ void *handle = NULL;
+ ss_data *info = ss_info(sci_idx);
+ const char **t, *libpath = 0;
+ char *tmp, *cp, *next;
+ char **(**completion_func)(const char *, int, int);
+
+ if (info->readline_handle)
+ return;
+
+ libpath = ss_safe_getenv("SS_READLINE_PATH");
+ if (!libpath)
+ libpath = DEFAULT_LIBPATH;
+ if (*libpath == 0 || !strcmp(libpath, "none"))
+ return;
+
+ tmp = malloc(strlen(libpath)+1);
+ if (!tmp)
+ return;
+ strcpy(tmp, libpath);
+ for (cp = tmp; cp; cp = next) {
+ next = strchr(cp, ':');
+ if (next)
+ *next++ = 0;
+ if (*cp == 0)
+ continue;
+ if ((handle = dlopen(cp, RTLD_NOW))) {
+ /* printf("Using %s for readline library\n", cp); */
+ break;
+ }
+ }
+ free(tmp);
+ if (!handle)
+ return;
+
+ info->readline_handle = handle;
+ info->readline = (char *(*)(const char *))
+ dlsym(handle, "readline");
+ info->add_history = (void (*)(const char *))
+ dlsym(handle, "add_history");
+ info->redisplay = (void (*)(void))
+ dlsym(handle, "rl_forced_update_display");
+ info->rl_completion_matches = (char **(*)(const char *,
+ char *(*)(const char *, int)))
+ dlsym(handle, "rl_completion_matches");
+ if ((t = dlsym(handle, "rl_readline_name")) != NULL)
+ *t = info->subsystem_name;
+ if ((completion_func =
+ dlsym(handle, "rl_attempted_completion_function")) != NULL)
+ *completion_func = ss_rl_completion;
+ info->readline_shutdown = ss_release_readline;
+}
+#else
+void ss_get_readline(int sci_idx __SS_ATTR((unused)))
+{
+}
+#endif
diff --git a/lib/ss/help.c b/lib/ss/help.c
new file mode 100644
index 0000000..54c78f2
--- /dev/null
+++ b/lib/ss/help.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#ifdef NEED_SYS_FCNTL_H
+/* just for O_* */
+#include <sys/fcntl.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include "ss_internal.h"
+
+void ss_help(int argc, char const * const *argv, int sci_idx, pointer info_ptr)
+{
+ char *buffer;
+ char const *request_name;
+ int code;
+ int fd, child;
+ register int idx;
+ register ss_data *info;
+
+ request_name = ss_current_request(sci_idx, &code);
+ if (code != 0) {
+ ss_perror(sci_idx, code, "");
+ return; /* no ss_abort_line, if invalid invocation */
+ }
+ if (argc == 1) {
+ ss_list_requests(argc, argv, sci_idx, info_ptr);
+ return;
+ }
+ else if (argc != 2) {
+ /* should do something better than this */
+ buffer = malloc(80+2*strlen(request_name));
+ if (!buffer) {
+ ss_perror(sci_idx, 0,
+ "couldn't allocate memory to print usage message");
+ return;
+ }
+ sprintf(buffer, "usage:\n\t%s [topic|command]\nor\t%s\n",
+ request_name, request_name);
+ ss_perror(sci_idx, 0, buffer);
+ free(buffer);
+ return;
+ }
+ info = ss_info(sci_idx);
+ if (info->info_dirs == (char **)NULL) {
+ ss_perror(sci_idx, SS_ET_NO_INFO_DIR, (char *)NULL);
+ return;
+ }
+ if (info->info_dirs[0] == (char *)NULL) {
+ ss_perror(sci_idx, SS_ET_NO_INFO_DIR, (char *)NULL);
+ return;
+ }
+ for (fd = -1, idx = 0; info->info_dirs[idx] != (char *)NULL; idx++) {
+ buffer = malloc(strlen (info->info_dirs[idx]) + 1 +
+ strlen (argv[1]) + 6);
+ if (!buffer) {
+ ss_perror(sci_idx, 0,
+ "couldn't allocate memory for help filename");
+ return;
+ }
+ (void) strcpy(buffer, info->info_dirs[idx]);
+ (void) strcat(buffer, "/");
+ (void) strcat(buffer, argv[1]);
+ (void) strcat(buffer, ".info");
+ fd = open(buffer, O_RDONLY);
+ free(buffer);
+ if (fd >= 0)
+ break;
+ }
+ if (fd < 0) {
+#define MSG "No info found for "
+ char *buf = malloc(strlen (MSG) + strlen (argv[1]) + 1);
+ if (!buf) {
+ ss_perror(sci_idx, 0,
+ "couldn't allocate memory to print error message");
+ return;
+ }
+ strcpy(buf, MSG);
+ strcat(buf, argv[1]);
+ ss_perror(sci_idx, 0, buf);
+ free(buf);
+ return;
+ }
+ switch (child = fork()) {
+ case -1:
+ ss_perror(sci_idx, errno, "Can't fork for pager");
+ (void) close(fd);
+ return;
+ case 0:
+ (void) dup2(fd, 0); /* put file on stdin */
+ ss_page_stdin();
+ default:
+ (void) close(fd); /* what can we do if it fails? */
+ while (wait(NULL) != child) {
+ /* do nothing if wrong pid */
+ };
+ }
+}
+
+#ifndef HAVE_DIRENT_H
+#include <sys/dir.h>
+#else
+#include <dirent.h>
+#endif
+
+void ss_add_info_dir(int sci_idx, char *info_dir, int *code_ptr)
+{
+ register ss_data *info;
+ DIR *d;
+ int n_dirs;
+ register char **dirs;
+
+ info = ss_info(sci_idx);
+ if (info_dir == NULL || *info_dir == '\0') {
+ *code_ptr = SS_ET_NO_INFO_DIR;
+ return;
+ }
+ if ((d = opendir(info_dir)) == (DIR *)NULL) {
+ *code_ptr = errno;
+ return;
+ }
+ closedir(d);
+ dirs = info->info_dirs;
+ for (n_dirs = 0; dirs[n_dirs] != (char *)NULL; n_dirs++)
+ ; /* get number of non-NULL dir entries */
+ dirs = (char **)realloc((char *)dirs,
+ (unsigned)(n_dirs + 2)*sizeof(char *));
+ if (dirs == (char **)NULL) {
+ *code_ptr = ENOMEM;
+ return;
+ }
+ info->info_dirs = dirs;
+ dirs[n_dirs + 1] = (char *)NULL;
+ dirs[n_dirs] = malloc((unsigned)strlen(info_dir)+1);
+ if (dirs[n_dirs] == (char *)NULL) {
+ *code_ptr = ENOMEM;
+ return;
+ }
+ strcpy(dirs[n_dirs], info_dir);
+ *code_ptr = 0;
+}
+
+void ss_delete_info_dir(int sci_idx, char *info_dir, int *code_ptr)
+{
+ register char **i_d;
+ register char **info_dirs;
+
+ info_dirs = ss_info(sci_idx)->info_dirs;
+ for (i_d = info_dirs; *i_d; i_d++) {
+ if (!strcmp(*i_d, info_dir)) {
+ while (*i_d) {
+ *i_d = *(i_d+1);
+ i_d++;
+ }
+ *code_ptr = 0;
+ return;
+ }
+ }
+ *code_ptr = SS_ET_NO_INFO_DIR;
+}
diff --git a/lib/ss/invocation.c b/lib/ss/invocation.c
new file mode 100644
index 0000000..7d7458a
--- /dev/null
+++ b/lib/ss/invocation.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#ifdef HAS_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "ss_internal.h"
+#define size sizeof(ss_data *)
+#ifdef HAVE_DLOPEN
+#include <dlfcn.h>
+#endif
+#include <errno.h>
+
+int ss_create_invocation(const char *subsystem_name, const char *version_string,
+ void *info_ptr, ss_request_table *request_table_ptr,
+ int *code_ptr)
+{
+ int sci_idx;
+ ss_data *new_table = NULL;
+ ss_data **table = NULL;
+ ss_data **realloc_table = NULL;
+
+ *code_ptr = 0;
+ table = _ss_table;
+ new_table = (ss_data *) malloc(sizeof(ss_data));
+ if (!new_table)
+ goto out;
+ memset(new_table, 0, sizeof(ss_data));
+
+ if (table == (ss_data **) NULL) {
+ table = (ss_data **) malloc(2 * size);
+ if (!table)
+ goto out;
+ table[0] = table[1] = (ss_data *)NULL;
+ }
+ initialize_ss_error_table ();
+
+ for (sci_idx = 1; table[sci_idx] != (ss_data *)NULL; sci_idx++)
+ ;
+ realloc_table = (ss_data **) realloc((char *)table,
+ ((unsigned)sci_idx+2)*size);
+ if (realloc_table == NULL)
+ goto out;
+
+ table = realloc_table;
+ table[sci_idx+1] = (ss_data *) NULL;
+ table[sci_idx] = new_table;
+
+ new_table->subsystem_name = subsystem_name;
+ new_table->subsystem_version = version_string;
+ new_table->argv = (char **)NULL;
+ new_table->current_request = (char *)NULL;
+ new_table->info_dirs = (char **)malloc(sizeof(char *));
+ if (!new_table->info_dirs)
+ goto out;
+
+ *new_table->info_dirs = (char *)NULL;
+ new_table->info_ptr = info_ptr;
+ new_table->prompt = malloc((unsigned)strlen(subsystem_name)+4);
+ if (!new_table->prompt)
+ goto out;
+
+ strcpy(new_table->prompt, subsystem_name);
+ strcat(new_table->prompt, ": ");
+#ifdef silly
+ new_table->abbrev_info = ss_abbrev_initialize("/etc/passwd", code_ptr);
+#else
+ new_table->abbrev_info = NULL;
+#endif
+ new_table->flags.escape_disabled = 0;
+ new_table->flags.abbrevs_disabled = 0;
+ new_table->rqt_tables =
+ (ss_request_table **) calloc(2, sizeof(ss_request_table *));
+ if (!new_table->rqt_tables)
+ goto out;
+
+ *(new_table->rqt_tables) = request_table_ptr;
+ *(new_table->rqt_tables+1) = (ss_request_table *) NULL;
+
+ new_table->readline_handle = 0;
+ new_table->readline_shutdown = 0;
+ new_table->readline = 0;
+ new_table->add_history = 0;
+ new_table->redisplay = 0;
+ new_table->rl_completion_matches = 0;
+ _ss_table = table;
+#if defined(HAVE_DLOPEN) && defined(SHARED_ELF_LIB)
+ ss_get_readline(sci_idx);
+#endif
+ return(sci_idx);
+
+out:
+ if (new_table) {
+ free(new_table->prompt);
+ free(new_table->info_dirs);
+ }
+ free(new_table);
+ free(table);
+ *code_ptr = ENOMEM;
+ return 0;
+
+}
+
+void
+ss_delete_invocation(int sci_idx)
+{
+ register ss_data *t;
+ int ignored_code;
+
+ t = ss_info(sci_idx);
+ free(t->prompt);
+ free(t->rqt_tables);
+ while(t->info_dirs[0] != (char *)NULL)
+ ss_delete_info_dir(sci_idx, t->info_dirs[0], &ignored_code);
+ free(t->info_dirs);
+#if defined(HAVE_DLOPEN) && defined(SHARED_ELF_LIB)
+ if (t->readline_shutdown)
+ (*t->readline_shutdown)(t);
+#endif
+ free(t);
+}
diff --git a/lib/ss/list_rqs.c b/lib/ss/list_rqs.c
new file mode 100644
index 0000000..89e37bb
--- /dev/null
+++ b/lib/ss/list_rqs.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+#include "config.h"
+#include "ss_internal.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+
+typedef void sigret_t;
+
+void ss_list_requests(int argc __SS_ATTR((unused)),
+ const char * const *argv __SS_ATTR((unused)),
+ int sci_idx, void *infop __SS_ATTR((unused)))
+{
+ ss_request_entry *entry;
+ char const * const *name;
+ int i, spacing;
+ ss_request_table **table;
+
+ FILE *output;
+ int fd;
+ sigset_t omask, igmask;
+ sigret_t (*func)(int);
+#ifndef NO_FORK
+ int waitb;
+#endif
+
+ sigemptyset(&igmask);
+ sigaddset(&igmask, SIGINT);
+ sigprocmask(SIG_BLOCK, &igmask, &omask);
+ func = signal(SIGINT, SIG_IGN);
+ fd = ss_pager_create();
+ if (fd < 0) {
+ perror("ss_pager_create");
+ (void) signal(SIGINT, func);
+ return;
+ }
+ output = fdopen(fd, "w");
+ if (!output) {
+ perror("fdopen");
+ close(fd);
+ (void) signal(SIGINT, func);
+ return;
+ }
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+
+ fprintf (output, "Available %s requests:\n\n",
+ ss_info (sci_idx) -> subsystem_name);
+
+ for (table = ss_info(sci_idx)->rqt_tables; *table; table++) {
+ entry = (*table)->requests;
+ for (; entry->command_names; entry++) {
+ spacing = -2;
+ if (entry->flags & SS_OPT_DONT_LIST)
+ continue;
+ for (name = entry->command_names; *name; name++) {
+ int len = strlen(*name);
+ fputs(*name, output);
+ spacing += len + 2;
+ if (name[1]) {
+ fputs(", ", output);
+ }
+ }
+ if (spacing > 23) {
+ fputc('\n', output);
+ spacing = 0;
+ }
+ for (i = 0; i < 25 - spacing; i++)
+ fputc(' ', output);
+ fputs(entry->info_string, output);
+ fputc('\n', output);
+ }
+ }
+ fclose(output);
+#ifndef NO_FORK
+ wait(&waitb);
+#endif
+ (void) signal(SIGINT, func);
+}
diff --git a/lib/ss/listen.c b/lib/ss/listen.c
new file mode 100644
index 0000000..9578c3e
--- /dev/null
+++ b/lib/ss/listen.c
@@ -0,0 +1,200 @@
+/*
+ * Listener loop for subsystem library libss.a.
+ *
+ * $Header$
+ * $Locker$
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#include "ss_internal.h"
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+
+typedef void sigret_t;
+
+static ss_data *current_info;
+static jmp_buf listen_jmpb;
+static sigret_t (*sig_cont)(int);
+
+static sigret_t print_prompt(int sig __SS_ATTR((unused)))
+{
+ if (current_info->redisplay)
+ (*current_info->redisplay)();
+ else {
+ (void) fputs(current_info->prompt, stdout);
+ (void) fflush(stdout);
+ }
+}
+
+static sigret_t listen_int_handler(int sig __SS_ATTR((unused)))
+{
+ putc('\n', stdout);
+ signal(SIGINT, listen_int_handler);
+ longjmp(listen_jmpb, 1);
+}
+
+int ss_listen (int sci_idx)
+{
+ char *cp;
+ ss_data *info;
+ sigret_t (*sig_int)(int), (*old_sig_cont)(int);
+ char input[BUFSIZ];
+ sigset_t omask, igmask;
+ int code;
+ jmp_buf old_jmpb;
+ ss_data *old_info = current_info;
+ char *line;
+
+ current_info = info = ss_info(sci_idx);
+ sig_cont = (sigret_t (*)(int)) 0;
+ info->abort = 0;
+ sigemptyset(&igmask);
+ sigaddset(&igmask, SIGINT);
+ sigprocmask(SIG_BLOCK, &igmask, &omask);
+ memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
+ sig_int = signal(SIGINT, listen_int_handler);
+ setjmp(listen_jmpb);
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
+
+ while(!info->abort) {
+ old_sig_cont = sig_cont;
+ sig_cont = signal(SIGCONT, print_prompt);
+ if (sig_cont == print_prompt)
+ sig_cont = old_sig_cont;
+ if (info->readline) {
+ line = (*info->readline)(current_info->prompt);
+ } else {
+ print_prompt(0);
+ if (fgets(input, BUFSIZ, stdin) == input)
+ line = input;
+ else
+ line = NULL;
+
+ input[BUFSIZ-1] = 0;
+ }
+ if (line == NULL) {
+ code = SS_ET_EOF;
+ (void) signal(SIGCONT, sig_cont);
+ goto egress;
+ }
+
+ cp = strchr(line, '\n');
+ if (cp) {
+ *cp = '\0';
+ if (cp == line)
+ continue;
+ }
+ (void) signal(SIGCONT, sig_cont);
+ if (info->add_history)
+ (*info->add_history)(line);
+
+ code = ss_execute_line (sci_idx, line);
+ if (code == SS_ET_COMMAND_NOT_FOUND) {
+ register char *c = line;
+ while (*c == ' ' || *c == '\t')
+ c++;
+ cp = strchr (c, ' ');
+ if (cp)
+ *cp = '\0';
+ cp = strchr (c, '\t');
+ if (cp)
+ *cp = '\0';
+ ss_error (sci_idx, 0,
+ "Unknown request \"%s\". Type \"?\" for a request list.",
+ c);
+ }
+ if (info->readline)
+ free(line);
+ }
+ code = 0;
+egress:
+ (void) signal(SIGINT, sig_int);
+ memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
+ current_info = old_info;
+ return code;
+}
+
+void ss_abort_subsystem(int sci_idx, int code)
+{
+ ss_info(sci_idx)->abort = 1;
+ ss_info(sci_idx)->exit_status = code;
+
+}
+
+void ss_quit(int argc __SS_ATTR((unused)),
+ const char * const *argv __SS_ATTR((unused)),
+ int sci_idx, pointer infop __SS_ATTR((unused)))
+{
+ ss_abort_subsystem(sci_idx, 0);
+}
+
+#ifdef HAVE_DLOPEN
+#define get_request(tbl,idx) ((tbl) -> requests + (idx))
+
+static char *cmd_generator(const char *text, int state)
+{
+ static int len;
+ static ss_request_table **rqtbl;
+ static int curr_rqt;
+ static char const * const * name;
+ ss_request_entry *request;
+ char *ret;
+
+ if (state == 0) {
+ len = strlen(text);
+ rqtbl = current_info->rqt_tables;
+ if (!rqtbl || !*rqtbl)
+ return 0;
+ curr_rqt = 0;
+ name = 0;
+ }
+
+ while (1) {
+ if (!name || !*name) {
+ request = get_request(*rqtbl, curr_rqt++);
+ name = request->command_names;
+ if (!name) {
+ rqtbl++;
+ if (*rqtbl) {
+ curr_rqt = 0;
+ continue;
+ } else
+ break;
+ }
+ }
+ if (strncmp(*name, text, len) == 0) {
+ ret = malloc(strlen(*name)+1);
+ if (ret)
+ strcpy(ret, *name);
+ name++;
+ return ret;
+ }
+ name++;
+ }
+
+ return 0;
+}
+
+char **ss_rl_completion(const char *text, int start,
+ int end __SS_ATTR((unused)))
+{
+ if ((start == 0) && current_info->rl_completion_matches)
+ return (*current_info->rl_completion_matches)
+ (text, cmd_generator);
+ return 0;
+}
+#endif
+
diff --git a/lib/ss/mit-sipb-copyright.h b/lib/ss/mit-sipb-copyright.h
new file mode 100644
index 0000000..ffcfc38
--- /dev/null
+++ b/lib/ss/mit-sipb-copyright.h
@@ -0,0 +1,19 @@
+/*
+
+Copyright 1987 by the Student Information Processing Board
+ of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose. It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/lib/ss/mk_cmds.1 b/lib/ss/mk_cmds.1
new file mode 100644
index 0000000..216e483
--- /dev/null
+++ b/lib/ss/mk_cmds.1
@@ -0,0 +1,59 @@
+.\" Copyright (c) 2003 Theodore Ts'o
+.\"
+.TH MK_CMDS 1 "2003" E2FSPROGS
+.SH NAME
+mk_cmds \- error table compiler
+.SH SYNOPSIS
+.B mk_cmds
+file
+.SH DESCRIPTION
+.B Mk_cmds
+converts a table listing command names and associated help messages
+into a C source file suitable for use with the
+.IR ss (3)
+library.
+
+The source file name must end with a suffix of ``.ct''; the file
+consists of a declaration supplying the name of the command table:
+
+.B command_table
+.I name
+
+followed by entries of the form:
+
+[
+.B request
+|
+.B unimplemented
+]
+.I name,
+"
+.I string
+"[, abbrev]...;
+
+and a final
+
+.B end
+
+to indicate the end of the table.
+
+A C source file is generated which should be compiled and linked
+with the object files use the ss library.
+
+A ``#'' in the source file is treated as a comment character, and all
+remaining text to the end of the source line will be ignored.
+
+.SH BUGS
+
+Since the original
+.B mk_cmds
+uses a very simple parser based on
+.IR yacc (1),
+and this current version of
+.B mk_cmds
+uses an awk/sed combination of scripts,
+its error recovery leaves much to be desired.
+
+.SH "SEE ALSO"
+ss (3)
+
diff --git a/lib/ss/mk_cmds.sh.in b/lib/ss/mk_cmds.sh.in
new file mode 100644
index 0000000..53282f4
--- /dev/null
+++ b/lib/ss/mk_cmds.sh.in
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+#
+
+DIR=@datadir@/ss
+AWK=@AWK@
+SED=sed
+
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+if test "x$1" = x ; then
+ echo "Usage: mk_cmds file"
+ exit 1
+fi
+
+if test -n "$_SS_DIR_OVERRIDE" ; then
+ DIR="$_SS_DIR_OVERRIDE";
+fi
+
+if test ! -f $DIR/ct_c.sed || test ! -f $DIR/ct_c.awk ; then
+ echo "mk_cmds: Couldn't find mk_cmds's template files."
+ exit 1
+fi
+
+FILE="$1"
+ROOT=`echo $1 | sed -e s/.ct$//`
+BASE=`basename "$ROOT"`
+TMP="ct$$.c"
+
+if test ! -f "$FILE" ; then
+ echo "mk_cmds: $FILE: File not found"
+ exit 1;
+fi
+
+${SED} -f "${DIR}/ct_c.sed" "${FILE}" \
+ | ${AWK} -f "${DIR}/ct_c.awk" "rootname=${ROOT}" "outfile=${TMP}" -
+
+if grep "^#__ERROR_IN_FILE" "${TMP}" > /dev/null; then
+ rm "${TMP}"
+ exit 1
+else
+ rm -f "${BASE}.c"
+ mv -f "${TMP}" "${BASE}.c"
+ chmod a-w "${BASE}.c"
+ exit 0
+fi
diff --git a/lib/ss/pager.c b/lib/ss/pager.c
new file mode 100644
index 0000000..ba32b20
--- /dev/null
+++ b/lib/ss/pager.c
@@ -0,0 +1,152 @@
+/*
+ * Pager: Routines to create a "more" running out of a particular file
+ * descriptor.
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ss_internal.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <signal.h>
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
+#if (!defined(HAVE_PRCTL) && defined(linux))
+#include <sys/syscall.h>
+#endif
+
+static char MORE[] = "more";
+extern char *getenv PROTOTYPE((const char *));
+
+char *ss_safe_getenv(const char *arg)
+{
+ if ((getuid() != geteuid()) || (getgid() != getegid()))
+ return NULL;
+#if HAVE_PRCTL
+ if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ return NULL;
+#else
+#if (defined(linux) && defined(SYS_prctl))
+ if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ return NULL;
+#endif
+#endif
+
+#if defined(HAVE_SECURE_GETENV)
+ return secure_getenv(arg);
+#elif defined(HAVE___SECURE_GETENV)
+ return __secure_getenv(arg);
+#else
+ return getenv(arg);
+#endif
+}
+
+/*
+ * this needs a *lot* of work....
+ *
+ * run in same process
+ * handle SIGINT sensibly
+ * allow finer control -- put-page-break-here
+ */
+
+#ifndef NO_FORK
+int ss_pager_create(void)
+{
+ int filedes[2];
+
+ if (pipe(filedes) != 0)
+ return(-1);
+
+ switch(fork()) {
+ case -1:
+ return(-1);
+ case 0:
+ /*
+ * Child; dup read half to 0, close all but 0, 1, and 2
+ */
+ if (dup2(filedes[0], 0) == -1)
+ exit(1);
+ ss_page_stdin();
+ default:
+ /*
+ * Parent: close "read" side of pipe, return
+ * "write" side.
+ */
+ (void) close(filedes[0]);
+ return(filedes[1]);
+ }
+}
+#else /* don't fork */
+int ss_pager_create()
+{
+ int fd;
+ fd = open("/dev/tty", O_WRONLY, 0);
+ return fd;
+}
+#endif
+
+static int write_all(int fd, char *buf, size_t count)
+{
+ ssize_t ret;
+ int c = 0;
+
+ while (count > 0) {
+ ret = write(fd, buf, count);
+ if (ret < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ return -1;
+ }
+ count -= ret;
+ buf += ret;
+ c += ret;
+ }
+ return c;
+}
+
+void ss_page_stdin(void)
+{
+ int i;
+ sigset_t mask;
+
+ for (i = 3; i < 32; i++)
+ (void) close(i);
+ (void) signal(SIGINT, SIG_DFL);
+ sigprocmask(SIG_BLOCK, 0, &mask);
+ sigdelset(&mask, SIGINT);
+ sigprocmask(SIG_SETMASK, &mask, 0);
+ if (_ss_pager_name == (char *)NULL) {
+ if ((_ss_pager_name = ss_safe_getenv("PAGER")) == (char *)NULL)
+ _ss_pager_name = MORE;
+ }
+ (void) execlp(_ss_pager_name, _ss_pager_name, (char *) NULL);
+ {
+ /* minimal recovery if pager program isn't found */
+ char buf[80];
+ register int n;
+ while ((n = read(0, buf, 80)) > 0)
+ write_all(1, buf, n);
+ }
+ exit(errno);
+}
diff --git a/lib/ss/parse.c b/lib/ss/parse.c
new file mode 100644
index 0000000..7c6c679
--- /dev/null
+++ b/lib/ss/parse.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#ifdef HAS_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ss_internal.h"
+
+enum parse_mode { WHITESPACE, TOKEN, QUOTED_STRING };
+
+/*
+ * parse(line_ptr, argc_ptr)
+ *
+ * Function:
+ * Parses line, dividing at whitespace, into tokens, returns
+ * the "argc" and "argv" values.
+ * Arguments:
+ * line_ptr (char *)
+ * Pointer to text string to be parsed.
+ * argc_ptr (int *)
+ * Where to put the "argc" (number of tokens) value.
+ * Returns:
+ * argv (char **)
+ * Series of pointers to parsed tokens.
+ */
+
+#define NEW_ARGV(old,n) (char **)realloc((char *)old,\
+ (unsigned)(n+2)*sizeof(char*))
+
+char **ss_parse(int sci_idx, register char *line_ptr, int *argc_ptr)
+{
+ register char **argv, **new_argv, *cp;
+ register int argc;
+ register enum parse_mode parse_mode;
+
+ argv = (char **) malloc (sizeof(char *));
+ if (argv == (char **)NULL) {
+ ss_error(sci_idx, errno, "Can't allocate storage");
+ *argc_ptr = 0;
+ return(argv);
+ }
+ *argv = (char *)NULL;
+
+ argc = 0;
+
+ parse_mode = WHITESPACE; /* flushing whitespace */
+ cp = line_ptr; /* cp is for output */
+ while (1) {
+#ifdef DEBUG
+ {
+ printf ("character `%c', mode %d\n", *line_ptr, parse_mode);
+ }
+#endif
+ while (parse_mode == WHITESPACE) {
+ if (*line_ptr == '\0')
+ goto end_of_line;
+ if (*line_ptr == ' ' || *line_ptr == '\t') {
+ line_ptr++;
+ continue;
+ }
+ if (*line_ptr == '"') {
+ /* go to quoted-string mode */
+ parse_mode = QUOTED_STRING;
+ cp = line_ptr++;
+ new_argv = NEW_ARGV (argv, argc);
+ if (new_argv == NULL) {
+ free(argv);
+ *argc_ptr = 0;
+ return NULL;
+ }
+ argv = new_argv;
+ argv[argc++] = cp;
+ argv[argc] = NULL;
+ }
+ else {
+ /* random-token mode */
+ parse_mode = TOKEN;
+ cp = line_ptr;
+ new_argv = NEW_ARGV (argv, argc);
+ if (new_argv == NULL) {
+ free(argv);
+ *argc_ptr = 0;
+ return NULL;
+ }
+ argv = new_argv;
+ argv[argc++] = line_ptr;
+ argv[argc] = NULL;
+ }
+ }
+ while (parse_mode == TOKEN) {
+ if (*line_ptr == '\0') {
+ *cp++ = '\0';
+ goto end_of_line;
+ }
+ else if (*line_ptr == ' ' || *line_ptr == '\t') {
+ *cp++ = '\0';
+ line_ptr++;
+ parse_mode = WHITESPACE;
+ }
+ else if (*line_ptr == '"') {
+ line_ptr++;
+ parse_mode = QUOTED_STRING;
+ }
+ else {
+ *cp++ = *line_ptr++;
+ }
+ }
+ while (parse_mode == QUOTED_STRING) {
+ if (*line_ptr == '\0') {
+ ss_error (sci_idx, 0,
+ "Unbalanced quotes in command line");
+ free (argv);
+ *argc_ptr = 0;
+ return NULL;
+ }
+ else if (*line_ptr == '"') {
+ if (*++line_ptr == '"') {
+ *cp++ = '"';
+ line_ptr++;
+ }
+ else {
+ parse_mode = TOKEN;
+ }
+ }
+ else {
+ *cp++ = *line_ptr++;
+ }
+ }
+ }
+end_of_line:
+ *argc_ptr = argc;
+#ifdef DEBUG
+ {
+ int i;
+ printf ("argc = %d\n", argc);
+ for (i = 0; i <= argc; i++)
+ printf ("\targv[%2d] = `%s'\n", i,
+ argv[i] ? argv[i] : "<NULL>");
+ }
+#endif
+ return(argv);
+}
diff --git a/lib/ss/prompt.c b/lib/ss/prompt.c
new file mode 100644
index 0000000..c56c2a0
--- /dev/null
+++ b/lib/ss/prompt.c
@@ -0,0 +1,31 @@
+/*
+ * prompt.c: Routines for retrieving and setting a prompt.
+ *
+ * $Header$
+ * $Locker$
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include "ss_internal.h"
+
+void ss_set_prompt(int sci_idx, char *new_prompt)
+{
+ ss_info(sci_idx)->prompt = new_prompt;
+}
+
+char *ss_get_prompt(int sci_idx)
+{
+ return(ss_info(sci_idx)->prompt);
+}
diff --git a/lib/ss/request_tbl.c b/lib/ss/request_tbl.c
new file mode 100644
index 0000000..135cb28
--- /dev/null
+++ b/lib/ss/request_tbl.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ss_internal.h"
+
+#define ssrt ss_request_table /* for some readable code... */
+
+void ss_add_request_table(int sci_idx, ssrt *rqtbl_ptr, int position, int *code_ptr)
+{
+ register ss_data *info;
+ register int i, size;
+ ssrt **t;
+
+ info = ss_info(sci_idx);
+ for (size=0; info->rqt_tables[size] != (ssrt *)NULL; size++)
+ ;
+ /* size == C subscript of NULL == #elements */
+ size += 2; /* new element, and NULL */
+ t = (ssrt **)realloc(info->rqt_tables, (unsigned)size*sizeof(ssrt *));
+ if (t == (ssrt **)NULL) {
+ *code_ptr = errno;
+ return;
+ }
+ info->rqt_tables = t;
+ if (position > size - 2)
+ position = size - 2;
+
+ if (size > 1)
+ for (i = size - 2; i >= position; i--)
+ info->rqt_tables[i+1] = info->rqt_tables[i];
+
+ info->rqt_tables[position] = rqtbl_ptr;
+ info->rqt_tables[size-1] = (ssrt *)NULL;
+ *code_ptr = 0;
+}
+
+void ss_delete_request_table(int sci_idx, ssrt *rqtbl_ptr, int *code_ptr)
+{
+ register ss_data *info;
+ register ssrt **rt1, **rt2;
+
+ *code_ptr = SS_ET_TABLE_NOT_FOUND;
+ info = ss_info(sci_idx);
+ rt1 = info->rqt_tables;
+ for (rt2 = rt1; *rt1; rt1++) {
+ if (*rt1 != rqtbl_ptr) {
+ *rt2++ = *rt1;
+ *code_ptr = 0;
+ }
+ }
+ *rt2 = (ssrt *)NULL;
+ return;
+}
diff --git a/lib/ss/requests.c b/lib/ss/requests.c
new file mode 100644
index 0000000..33ce5d2
--- /dev/null
+++ b/lib/ss/requests.c
@@ -0,0 +1,66 @@
+/*
+ * Various minor routines...
+ *
+ * Copyright 1987, 1988, 1989 by MIT
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include "ss_internal.h"
+
+#define DECLARE(name) void name(int argc,const char * const *argv, \
+ int sci_idx, void *infop)
+
+/*
+ * ss_self_identify -- assigned by default to the "." request
+ */
+void ss_self_identify(int argc __SS_ATTR((unused)),
+ const char * const *argv __SS_ATTR((unused)),
+ int sci_idx, void *infop __SS_ATTR((unused)))
+{
+ register ss_data *info = ss_info(sci_idx);
+ printf("%s version %s\n", info->subsystem_name,
+ info->subsystem_version);
+}
+
+/*
+ * ss_subsystem_name -- print name of subsystem
+ */
+void ss_subsystem_name(int argc __SS_ATTR((unused)),
+ const char * const *argv __SS_ATTR((unused)),
+ int sci_idx,
+ void *infop __SS_ATTR((unused)))
+{
+ printf("%s\n", ss_info(sci_idx)->subsystem_name);
+}
+
+/*
+ * ss_subsystem_version -- print version of subsystem
+ */
+void ss_subsystem_version(int argc __SS_ATTR((unused)),
+ const char * const *argv __SS_ATTR((unused)),
+ int sci_idx,
+ void *infop __SS_ATTR((unused)))
+{
+ printf("%s\n", ss_info(sci_idx)->subsystem_version);
+}
+
+/*
+ * ss_unimplemented -- routine not implemented (should be
+ * set up as (dont_list,dont_summarize))
+ */
+void ss_unimplemented(int argc __SS_ATTR((unused)),
+ const char * const *argv __SS_ATTR((unused)),
+ int sci_idx, void *infop __SS_ATTR((unused)))
+{
+ ss_perror(sci_idx, SS_ET_UNIMPLEMENTED, "");
+}
diff --git a/lib/ss/ss.h b/lib/ss/ss.h
new file mode 100644
index 0000000..7333ffc
--- /dev/null
+++ b/lib/ss/ss.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ *
+ * This quote is just too good to not pass on:
+ *
+ * "BTW, I would have rejected the name Story Server because its
+ * initials are SS, the name of the secret police in Nazi
+ * Germany, probably the most despised pair of letters in western
+ * culture." --- http://scriptingnewsarchive.userland.com/1999/12/13
+ *
+ * Let no one say political correctness isn't dead....
+ */
+
+#ifndef _ss_h
+#define _ss_h __FILE__
+
+#include <ss/ss_err.h>
+
+#define __SS_CONST const
+#define __SS_PROTO (int, const char * const *, int, void *)
+
+#ifdef __GNUC__
+#define __SS_ATTR(x) __attribute__(x)
+#else
+#define __SS_ATTR(x)
+#endif
+
+
+typedef __SS_CONST struct _ss_request_entry {
+ __SS_CONST char * __SS_CONST *command_names; /* whatever */
+ void (* __SS_CONST function) __SS_PROTO; /* foo */
+ __SS_CONST char * __SS_CONST info_string; /* NULL */
+ int flags; /* 0 */
+} ss_request_entry;
+
+typedef __SS_CONST struct _ss_request_table {
+ int version;
+ ss_request_entry *requests;
+} ss_request_table;
+
+#define SS_RQT_TBL_V2 2
+
+typedef struct _ss_rp_options { /* DEFAULT VALUES */
+ int version; /* SS_RP_V1 */
+ void (*unknown) __SS_PROTO; /* call for unknown command */
+ int allow_suspend;
+ int catch_int;
+} ss_rp_options;
+
+#define SS_RP_V1 1
+
+#define SS_OPT_DONT_LIST 0x0001
+#define SS_OPT_DONT_SUMMARIZE 0x0002
+
+void ss_help __SS_PROTO;
+#if 0
+char *ss_current_request(); /* This is actually a macro */
+#endif
+
+char *ss_name(int sci_idx);
+void ss_error (int, long, char const *, ...)
+ __SS_ATTR((format(printf, 3, 4)));
+void ss_perror (int, long, char const *);
+
+int ss_create_invocation(const char *, const char *, void *,
+ ss_request_table *, int *);
+void ss_delete_invocation(int);
+int ss_listen(int);
+int ss_execute_line(int, char *);
+void ss_add_request_table(int, ss_request_table *, int, int *);
+void ss_delete_request_table(int, ss_request_table *, int *);
+void ss_abort_subsystem(int sci_idx, int code);
+void ss_quit(int argc, const char * const *argv, int sci_idx, void *infop);
+void ss_self_identify(int argc, const char * const *argv, int sci_idx, void *infop);
+void ss_subsystem_name(int argc, const char * const *argv,
+ int sci_idx, void *infop);
+void ss_subsystem_version(int argc, const char * const *argv,
+ int sci_idx, void *infop);
+void ss_unimplemented(int argc, const char * const *argv,
+ int sci_idx, void *infop);
+void ss_set_prompt(int sci_idx, char *new_prompt);
+char *ss_get_prompt(int sci_idx);
+void ss_get_readline(int sci_idx);
+char *ss_safe_getenv(const char *arg);
+
+extern ss_request_table ss_std_requests;
+#endif /* _ss_h */
diff --git a/lib/ss/ss.pc.in b/lib/ss/ss.pc.in
new file mode 100644
index 0000000..5c9eccb
--- /dev/null
+++ b/lib/ss/ss.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ss
+Description: Subsystem command parsing library
+Version: @E2FSPROGS_VERSION@
+Requires.private: com_err
+Cflags: -I${includedir}/ss -I${includedir}
+Libs: -L${libdir} -lss
+Libs.private: @DLOPEN_LIB@
diff --git a/lib/ss/ss_err.et b/lib/ss/ss_err.et
new file mode 100644
index 0000000..80e9dfa
--- /dev/null
+++ b/lib/ss/ss_err.et
@@ -0,0 +1,39 @@
+ error_table ss
+
+ec SS_ET_SUBSYSTEM_ABORTED,
+ "Subsystem aborted"
+
+ec SS_ET_VERSION_MISMATCH,
+ "Version mismatch"
+
+ec SS_ET_NULL_INV,
+ "No current invocation"
+
+ec SS_ET_NO_INFO_DIR,
+ "No info directory"
+
+ec SS_ET_COMMAND_NOT_FOUND,
+ "Command not found"
+
+ec SS_ET_LINE_ABORTED,
+ "Command line aborted"
+
+ec SS_ET_EOF,
+ "End-of-file reached"
+
+ec SS_ET_PERMISSION_DENIED,
+ "Permission denied"
+
+ec SS_ET_TABLE_NOT_FOUND,
+ "Request table not found"
+
+ec SS_ET_NO_HELP_FILE,
+ "No info available"
+
+ec SS_ET_ESCAPE_DISABLED,
+ "Shell escapes are disabled"
+
+ec SS_ET_UNIMPLEMENTED,
+ "Sorry, this request is not yet implemented"
+
+ end
diff --git a/lib/ss/ss_internal.h b/lib/ss/ss_internal.h
new file mode 100644
index 0000000..7b1d23b
--- /dev/null
+++ b/lib/ss/ss_internal.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#ifndef _ss_ss_internal_h
+#define _ss_ss_internal_h __FILE__
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define PROTOTYPE(p) p
+typedef void * pointer;
+
+#include "ss.h"
+
+typedef char BOOL;
+
+typedef struct _ss_abbrev_entry {
+ char *name; /* abbrev name */
+ char **abbrev; /* new tokens to insert */
+ unsigned int beginning_of_line : 1;
+} ss_abbrev_entry;
+
+typedef struct _ss_abbrev_list {
+ int n_abbrevs;
+ ss_abbrev_entry *first_abbrev;
+} ss_abbrev_list;
+
+typedef struct {
+/* char *path; */
+ ss_abbrev_list abbrevs[127];
+} ss_abbrev_info;
+
+typedef struct _ss_data { /* init values */
+ /* this subsystem */
+ const char *subsystem_name;
+ const char *subsystem_version;
+ /* current request info */
+ int argc;
+ char **argv; /* arg list */
+ char const *current_request; /* primary name */
+ /* info directory for 'help' */
+ char **info_dirs;
+ /* to be extracted by subroutines */
+ pointer info_ptr; /* (void *) NULL */
+ /* for ss_listen processing */
+ char *prompt;
+ ss_request_table **rqt_tables;
+ ss_abbrev_info *abbrev_info;
+ struct {
+ unsigned int escape_disabled : 1,
+ abbrevs_disabled : 1;
+ } flags;
+ /*
+ * Dynamic usage of readline library if present
+ */
+ void *readline_handle;
+ void (*readline_shutdown)(struct _ss_data *info);
+ char *(*readline)(const char *);
+ void (*add_history)(const char *);
+ void (*redisplay)(void);
+ char **(*rl_completion_matches)(const char *,
+ char *(*completer)(const char *, int));
+ /* to get out */
+ int abort; /* exit subsystem */
+ int exit_status;
+} ss_data;
+
+#define CURRENT_SS_VERSION 1
+
+#define ss_info(sci_idx) (_ss_table[sci_idx])
+#define ss_current_request(sci_idx,code_ptr) \
+ (*code_ptr=0,ss_info(sci_idx)->current_request)
+void ss_add_info_dir (int sci_idx, char *info_dir, int *code_ptr);
+void ss_delete_info_dir (int sci_idx, char *info_dir, int *code_ptr);
+int ss_execute_line(int sci_idx, char *line_ptr);
+char **ss_parse(int sci_idx, char *line_ptr, int *argc_ptr);
+ss_abbrev_info *ss_abbrev_initialize(char *, int *);
+void ss_page_stdin(void) __SS_ATTR((noreturn));
+void ss_list_requests(int, char const * const *, int, pointer);
+int ss_execute_command(int sci_idx, char *argv[]);
+int ss_pager_create(void);
+char *ss_safe_getenv(const char *arg);
+char **ss_rl_completion(const char *text, int start, int end);
+
+extern ss_data **_ss_table;
+extern char *ss_et_msgs[];
+extern char *_ss_pager_name;
+
+#ifdef USE_SIGPROCMASK
+/* fake sigmask, sigblock, sigsetmask */
+#include <signal.h>
+#define sigmask(x) (1L<<(x)-1)
+#define sigsetmask(x) sigprocmask(SIG_SETMASK,&x,NULL)
+static int _fake_sigstore;
+#define sigblock(x) (_fake_sigstore=x,sigprocmask(SIG_BLOCK,&_fake_sigstore,0))
+#endif
+#endif /* _ss_internal_h */
diff --git a/lib/ss/std_rqs.ct b/lib/ss/std_rqs.ct
new file mode 100644
index 0000000..500288a
--- /dev/null
+++ b/lib/ss/std_rqs.ct
@@ -0,0 +1,46 @@
+ command_table ss_std_requests;
+
+ request ss_self_identify, "Identify the subsystem.",
+ ".",
+ (dont_list, dont_summarize);
+
+ request ss_help, "Display info on command or topic.",
+ help;
+
+ unimplemented
+ ss_list_help,
+ "List topics for which help is available.",
+ list_help, lh;
+
+ request ss_list_requests, "List available commands.",
+ list_requests, lr, "?";
+
+ request ss_quit, "Leave the subsystem.",
+ quit, q;
+
+ unimplemented
+ ss_abbrev,
+ "Enable/disable abbreviation processing of request lines.",
+ abbrev, ab;
+
+ unimplemented
+ ss_execute,
+ "Execute a UNIX command line.",
+ execute, e;
+
+ unimplemented
+ ss_summarize_requests,
+ "Produce a list of the most commonly used requests.",
+ "?";
+
+ request ss_subsystem_name,
+ "Return the name of this subsystem.",
+ subsystem_name,
+ (dont_list);
+
+ request ss_subsystem_version,
+ "Return the version of this subsystem.",
+ subsystem_version,
+ (dont_list);
+
+ end;
diff --git a/lib/ss/test_cmd.ct b/lib/ss/test_cmd.ct
new file mode 100644
index 0000000..fb49f78
--- /dev/null
+++ b/lib/ss/test_cmd.ct
@@ -0,0 +1,6 @@
+command_table test_cmds;
+
+request test_cmd, "Test command",
+ test_cmd, test;
+
+end;
diff --git a/lib/ss/test_script b/lib/ss/test_script
new file mode 100644
index 0000000..8af7fdc
--- /dev/null
+++ b/lib/ss/test_script
@@ -0,0 +1,8 @@
+test
+test foo bar quux
+test bar quux
+quux bar
+quux
+test quux
+quit
+test foo bar
diff --git a/lib/ss/test_script_expected b/lib/ss/test_script_expected
new file mode 100644
index 0000000..543f828
--- /dev/null
+++ b/lib/ss/test_script_expected
@@ -0,0 +1,22 @@
+test_ss 1.0. Type '?' for a list of commands.
+
+test_icount: test
+Hello, world!
+Args:
+test_icount: test foo bar quux
+Hello, world!
+Args: 'foo', 'bar', 'quux'
+test_icount: test bar quux
+Hello, world!
+Args: 'bar', 'quux'
+test_icount: quux bar
+test_ss: Command not found quux
+test_icount: quux
+test_ss: Command not found quux
+test_icount: test quux
+Hello, world!
+Args: 'quux'
+test_icount: quit
+test_icount: test foo bar
+Hello, world!
+Args: 'foo', 'bar'
diff --git a/lib/ss/test_ss.c b/lib/ss/test_ss.c
new file mode 100644
index 0000000..53ca99f
--- /dev/null
+++ b/lib/ss/test_ss.c
@@ -0,0 +1,151 @@
+/*
+ * test_ss.c
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose is hereby granted, provided that
+ * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. M.I.T. and the
+ * M.I.T. S.I.P.B. make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+
+ */
+
+#include "config.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#include <string.h>
+#include "ss.h"
+
+extern ss_request_table test_cmds;
+
+#define TRUE 1
+#define FALSE 0
+
+static char subsystem_name[] = "test_ss";
+static char version[] = "1.0";
+
+static int source_file(const char *cmd_file, int sci_idx)
+{
+ FILE *f;
+ char buf[256];
+ char *cp;
+ int exit_status = 0;
+ int retval;
+ int noecho;
+
+ if (strcmp(cmd_file, "-") == 0)
+ f = stdin;
+ else {
+ f = fopen(cmd_file, "r");
+ if (!f) {
+ perror(cmd_file);
+ exit(1);
+ }
+ }
+ fflush(stdout);
+ fflush(stderr);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+ while (!feof(f)) {
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ break;
+ if (buf[0] == '#')
+ continue;
+ noecho = 0;
+ if (buf[0] == '-') {
+ noecho = 1;
+ buf[0] = ' ';
+ }
+ cp = strchr(buf, '\n');
+ if (cp)
+ *cp = 0;
+ cp = strchr(buf, '\r');
+ if (cp)
+ *cp = 0;
+ if (!noecho)
+ printf("test_icount: %s\n", buf);
+ retval = ss_execute_line(sci_idx, buf);
+ if (retval) {
+ ss_perror(sci_idx, retval, buf);
+ exit_status++;
+ }
+ }
+ return exit_status;
+}
+
+int main(int argc, char **argv)
+{
+ int c, code;
+ char *request = (char *)NULL;
+ char *cmd_file = 0;
+ int sci_idx;
+ int exit_status = 0;
+
+ while ((c = getopt (argc, argv, "wR:f:")) != EOF) {
+ switch (c) {
+ case 'R':
+ request = optarg;
+ break;
+ case 'f':
+ cmd_file = optarg;
+ break;
+ default:
+ com_err(argv[0], 0, "Usage: test_ss [-R request] "
+ "[-f cmd_file]");
+ exit(1);
+ }
+ }
+
+ sci_idx = ss_create_invocation(subsystem_name, version,
+ (char *)NULL, &test_cmds, &code);
+ if (code) {
+ ss_perror(sci_idx, code, "creating invocation");
+ exit(1);
+ }
+
+ (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &code);
+ if (code) {
+ ss_perror (sci_idx, code, "adding standard requests");
+ exit (1);
+ }
+
+ printf("test_ss %s. Type '?' for a list of commands.\n\n",
+ version);
+
+ if (request) {
+ code = ss_execute_line(sci_idx, request);
+ if (code) {
+ ss_perror(sci_idx, code, request);
+ exit_status++;
+ }
+ } else if (cmd_file) {
+ exit_status = source_file(cmd_file, sci_idx);
+ } else {
+ ss_listen(sci_idx);
+ }
+
+ exit(exit_status);
+}
+
+
+void test_cmd (argc, argv)
+ int argc;
+ char **argv;
+{
+ printf("Hello, world!\n");
+ printf("Args: ");
+ while (++argv, --argc) {
+ printf("'%s'", *argv);
+ if (argc > 1)
+ fputs(", ", stdout);
+ }
+ putchar ('\n');
+}