diff options
Diffstat (limited to 'lib/ss')
-rw-r--r-- | lib/ss/Android.bp | 39 | ||||
-rw-r--r-- | lib/ss/Makefile.in | 234 | ||||
-rw-r--r-- | lib/ss/ct_c.awk | 75 | ||||
-rw-r--r-- | lib/ss/ct_c.sed | 160 | ||||
-rw-r--r-- | lib/ss/data.c | 20 | ||||
-rw-r--r-- | lib/ss/error.c | 77 | ||||
-rw-r--r-- | lib/ss/execute_cmd.c | 229 | ||||
-rw-r--r-- | lib/ss/get_readline.c | 100 | ||||
-rw-r--r-- | lib/ss/help.c | 185 | ||||
-rw-r--r-- | lib/ss/invocation.c | 132 | ||||
-rw-r--r-- | lib/ss/list_rqs.c | 92 | ||||
-rw-r--r-- | lib/ss/listen.c | 200 | ||||
-rw-r--r-- | lib/ss/mit-sipb-copyright.h | 19 | ||||
-rw-r--r-- | lib/ss/mk_cmds.1 | 59 | ||||
-rw-r--r-- | lib/ss/mk_cmds.sh.in | 56 | ||||
-rw-r--r-- | lib/ss/pager.c | 152 | ||||
-rw-r--r-- | lib/ss/parse.c | 158 | ||||
-rw-r--r-- | lib/ss/prompt.c | 31 | ||||
-rw-r--r-- | lib/ss/request_tbl.c | 68 | ||||
-rw-r--r-- | lib/ss/requests.c | 66 | ||||
-rw-r--r-- | lib/ss/ss.h | 96 | ||||
-rw-r--r-- | lib/ss/ss.pc.in | 12 | ||||
-rw-r--r-- | lib/ss/ss_err.et | 39 | ||||
-rw-r--r-- | lib/ss/ss_internal.h | 107 | ||||
-rw-r--r-- | lib/ss/std_rqs.ct | 46 | ||||
-rw-r--r-- | lib/ss/test_cmd.ct | 6 | ||||
-rw-r--r-- | lib/ss/test_script | 8 | ||||
-rw-r--r-- | lib/ss/test_script_expected | 22 | ||||
-rw-r--r-- | lib/ss/test_ss.c | 151 |
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'); +} |