diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..5ace4600 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..10e0ef77 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,108 @@ +name: release + +on: + push: + tags: [scallop-*] + branches: ['**'] + paths: + - ".github/workflows/release.yml" + workflow_dispatch: + +jobs: + release: + runs-on: ubuntu-latest + outputs: + release: ${{ steps.release.outputs.release }} + version: ${{ steps.release.outputs.version }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Get the release name + id: release + run: | + name=$(sed -rn "/^PACKAGE_NAME=/ s/^.*='(.*)'/\1/p" configure) + version=$(sed -rn "/^PACKAGE_VERSION=/ s/^.*='(.*)'/\1/p" configure) + release=${name}-${version} + ref=${{ github.ref_name }} + + # verify tag name matches configure script + if [[ ${{ github.ref_type }} == tag && ${ref} != ${release} ]]; then + echo "tag name ${ref} doesn't match package: ${release}" + exit 1 + fi + + echo "release=${release}" >> $GITHUB_OUTPUT + echo "version=${version}" >> $GITHUB_OUTPUT + + source: + needs: release + runs-on: ubuntu-latest + env: + RELEASE: ${{ needs.release.outputs.release }} + VERSION: ${{ needs.release.outputs.version }} + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + path: bash + + - name: Create release tarball + run: | + # remove unused files + rm -r bash/{doc,examples,tests,po} + + # copy non-hidden files + mkdir ${RELEASE} + cp -a bash/* ${RELEASE} + + # create tarball + tar -c -I "xz -9 -T0" -f ${RELEASE}.tar.xz ${RELEASE} + + - name: Build and install + run: | + cd ${RELEASE} + + # configure using required scallop options + ./configure-scallop + + # build static and shared libraries + make -j libscallop.a libscallop.so + + # install shared library and headers + sudo make install-library install-headers + + - name: Test + run: | + # verify shared library is installed and pkg-config works as expected + pkg-config --modversion scallop + pkg-config --exact-version ${VERSION} scallop + + - name: Upload artifact + uses: actions/upload-artifact@v7 + with: + name: source + path: ./*.tar.xz + if-no-files-found: error + retention-days: 3 + + publish: + if: startsWith(github.ref, 'refs/tags/') + needs: source + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + path: artifacts + merge-multiple: true + + - name: Create GitHub release + uses: softprops/action-gh-release@v3 + with: + files: artifacts/*.tar.xz + fail_on_unmatched_files: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..c60d54f4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,57 @@ +name: test + +on: + push: + branches: '**' + workflow_dispatch: + +jobs: + version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Get the package version + id: version + run: | + version=$(sed -rn "/^PACKAGE_VERSION=/ s/^.*='(.*)'/\1/p" configure) + date=${version##*.} + expected_date=$(date -u +"%Y%m%d") + + # verify patch date + if [[ ${date} != ${expected_date} ]]; then + echo outdated scallop patch date: ${date} + exit 1 + fi + + echo "version=${version}" >> $GITHUB_OUTPUT + + test: + needs: version + runs-on: ubuntu-latest + env: + VERSION: ${{ needs.version.outputs.version }} + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Build and install + run: | + # configure using required scallop options + ./configure-scallop + + # build static and shared libraries + make -j libscallop.a libscallop.so + + # install shared library and headers + sudo make install-library install-headers + + - name: Test + run: | + # verify shared library is installed and pkg-config works as expected + pkg-config --modversion scallop + pkg-config --exact-version ${VERSION} scallop diff --git a/Makefile.in b/Makefile.in index c4a882f7..218a22d9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -115,9 +115,13 @@ VERSOBJ = bashversion.$(OBJEXT) Program = bash$(EXEEXT) Version = @BASHVERS@ -PatchLevel = `$(BUILD_DIR)/$(VERSPROG) -p` +PatchLevel = $(shell $(BUILD_DIR)/$(VERSPROG) -p) RELSTATUS = @RELSTATUS@ +# scallop targets +StaticLibrary = libscallop.a +SharedLibrary = libscallop.so + Machine = @host_cpu@ OS = @host_os@ VENDOR = @host_vendor@ @@ -504,11 +508,11 @@ INSTALLED_HEADERS = shell.h bashjmp.h command.h syntax.h general.h error.h \ bashtypes.h xmalloc.h config-top.h config-bot.h \ bashintl.h bashansi.h bashjmp.h alias.h hashlib.h \ conftypes.h unwind_prot.h jobs.h siglist.h \ - execute_cmd.h + execute_cmd.h input.h pathexp.h flags.h # these can appear in either the source directory or the build directory and # are installed by install-headers HYBRID_HEADERS = y.tab.h -INSTALLED_BUILTINS_HEADERS = bashgetopt.h common.h getopt.h +INSTALLED_BUILTINS_HEADERS = builtext.h bashgetopt.h common.h getopt.h INSTALLED_INCLUDE_HEADERS = posixstat.h ansi_stdlib.h filecntl.h posixdir.h \ memalloc.h stdc.h posixjmp.h posixwait.h posixtime.h systimes.h \ unionwait.h maxpath.h shtty.h typemax.h ocache.h chartypes.h gettext.h \ @@ -636,6 +640,22 @@ $(Program): $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) .build ls -l $(Program) -$(SIZE) $(Program) +$(StaticLibrary): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(OBJECTS) + -for lib in $(BUILTINS_DEP) $(LIBDEP); do \ + for obj in $$($(AR) t $$lib); do \ + $(AR) q $@ $$(dirname $$lib)/$$obj ;\ + done ;\ + done + $(RANLIB) $@ + +$(SharedLibrary): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP) + $(RM) $@ + $(eval SCALLOP_LIBRARY = $(SharedLibrary).$(PACKAGE_VERSION)) + $(CC) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) $(LDFLAGS) \ + -Wl,-soname,${SCALLOP_LIBRARY} -shared -o ${SCALLOP_LIBRARY} $(OBJECTS) $(LIBS) + .build: $(SOURCES) config.h Makefile $(DEFDIR)/builtext.h version.h $(VERSPROG) @echo @echo " ***********************************************************" @@ -862,8 +882,8 @@ $(SUPPORT_DIR)/bashbug.sh: $(SUPPORT_DIR)/bashbug.sh.in CONFIG_FILES=$(SUPPORT_DIR)/bashbug.sh CONFIG_HEADERS= $(SHELL) ./config.status # comment out for distribution -$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 $(srcdir)/config.h.in - cd $(srcdir) && autoconf +#$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 $(srcdir)/config.h.in +# cd $(srcdir) && autoconf # for chet reconfig: force @@ -925,6 +945,11 @@ install: .made installdirs -( cd $(PO_DIR) ; $(MAKE) $(BASH_MAKEFLAGS) DESTDIR=$(DESTDIR) $@ ) -( cd $(LOADABLES_DIR) && $(MAKE) $(BASH_MAKEFLAGS) DESTDIR=$(DESTDIR) $@ ) +install-library: + @${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(libdir) + $(INSTALL) $(INSTALLMODE) $(SharedLibrary).* $(DESTDIR)$(libdir) + cd $(DESTDIR)$(libdir) && ln -sf $(SharedLibrary).* $(SharedLibrary) + install-strip: $(MAKE) $(BASH_MAKEFLAGS) INSTALL_PROGRAM='$(INSTALL_STRIP_PROGRAM)' \ prefix=${prefix} exec_prefix=${exec_prefix} \ @@ -966,7 +991,7 @@ install-headers: maybe-install-headers ${INSTALL_DATA} $(srcdir)/"$$hf" $(DESTDIR)$(headersdir)/$$hf || exit 1; \ fi ; \ done - -$(INSTALL_DATA) $(SUPPORT_DIR)/bash.pc $(DESTDIR)$(pkgconfigdir)/bash.pc + -$(INSTALL_DATA) $(SUPPORT_DIR)/$(PACKAGE).pc $(DESTDIR)$(pkgconfigdir)/$(PACKAGE).pc uninstall-headers-dirs: -$(RMDIR) $(DESTDIR)$(headersdir)/builtins $(DESTDIR)$(headersdir)/include @@ -981,7 +1006,7 @@ uninstall-headers: for hf in $${SDH} ; do \ ( cd $(DESTDIR)$(headersdir) && $(RM) $$(basename "$$hf") ) \ done - -( $(RM) $(DESTDIR)$(pkgconfigdir)/bash.pc ) + -( $(RM) $(DESTDIR)$(pkgconfigdir)/$(PACKAGE).pc ) # uninstall-headers-dirs -$(RMDIR) $(DESTDIR)$(headersdir)/builtins $(DESTDIR)$(headersdir)/include -$(RMDIR) $(DESTDIR)$(headersdir) @@ -1003,7 +1028,7 @@ LIB_SUBDIRS = ${RL_LIBDIR} ${HIST_LIBDIR} ${TERM_LIBDIR} ${GLOB_LIBDIR} \ ${INTL_LIBDIR} ${TILDE_LIBDIR} ${ALLOC_LIBDIR} ${SH_LIBDIR} basic-clean: - $(RM) $(OBJECTS) $(Program) bashbug + $(RM) $(OBJECTS) $(Program) $(StaticLibrary) $(SharedLibrary)* bashbug $(RM) .build .made version.h clean: basic-clean diff --git a/README.md b/README.md new file mode 100644 index 00000000..dd0f7033 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +[![ci](https://github.com/pkgcraft/bash/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/pkgcraft/bash/actions/workflows/test.yml) + +# bash + +Forked version of bash supporting shell interactions (e.g. writing builtins or +modifying variables, arrays, and functions) natively in rust via the scallop crate. + +## Development + +Note that the development workflow involves rebasing against upstream and force +pushing to keep the patch stack in order. diff --git a/builtins/common.c b/builtins/common.c index a681cee4..af66091d 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -80,47 +80,64 @@ sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL; shell. */ static void -builtin_error_prolog (void) +builtin_error_prolog (char *buf) { char *name; + int line; name = get_name_for_error (); - fprintf (stderr, "%s: ", name); + snprintf(buf, MAX_ERROR_LEN, "%s: ", name); - if (interactive_shell == 0) - fprintf (stderr, _("line %d: "), executing_line_number ()); + if (interactive_shell == 0) { + line = executing_line_number (); + if (line != 0) { + snprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), _("line %d: "), line); + } + } if (this_command_name && *this_command_name) - fprintf (stderr, "%s: ", this_command_name); + snprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), "%s: ", this_command_name); } void builtin_error (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; - builtin_error_prolog (); + builtin_error_prolog (&buf[0]); va_start (args, format); - - vfprintf (stderr, format, args); + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); - fprintf (stderr, "\n"); + +#if defined (BUILD_LIBRARY) + scallop_error(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif } void builtin_warning (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; - builtin_error_prolog (); - fprintf (stderr, _("warning: ")); + builtin_error_prolog (&buf[0]); +#if !defined (BUILD_LIBRARY) + snprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), _("warning: ")); +#endif va_start (args, format); - - vfprintf (stderr, format, args); + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); - fprintf (stderr, "\n"); + +#if defined (BUILD_LIBRARY) + scallop_warning(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif } /* Print a usage summary for the currently-executing builtin command. */ @@ -1081,3 +1098,35 @@ set_expand_once (int nval, int uwp) return oa; } #endif + +/* Register a given array of new builtins into the internal list. */ +int +register_builtins (struct builtin **new_builtins, size_t num_new_builtins) +{ + size_t total, size, replaced; + struct builtin *new_shell_builtins; + + total = num_shell_builtins + num_new_builtins; + size = (total + 1) * sizeof (struct builtin); + + new_shell_builtins = (struct builtin *)xmalloc (size); + FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, + num_shell_builtins * sizeof (struct builtin)); + for (replaced = 0; replaced < num_new_builtins; replaced++) + FASTCOPY ((char *)new_builtins[replaced], + (char *)&new_shell_builtins[num_shell_builtins + replaced], + sizeof (struct builtin)); + + new_shell_builtins[total].name = (char *)0; + new_shell_builtins[total].function = (sh_builtin_func_t *)0; + new_shell_builtins[total].flags = 0; + + if (shell_builtins != static_shell_builtins) + free (shell_builtins); + + shell_builtins = new_shell_builtins; + num_shell_builtins = total; + initialize_shell_builtins (); + + return (EXECUTION_SUCCESS); +} diff --git a/builtins/common.h b/builtins/common.h index a169f494..d21eee5f 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -22,6 +22,7 @@ # define __COMMON_H #include "stdc.h" +#include "builtins.h" #define ISOPTION(s, c) (s[0] == '-' && s[1] == c && !s[2]) #define ISHELP(s) (STREQ ((s), "--help")) @@ -88,6 +89,12 @@ extern void builtin_usage (void); extern void no_args (WORD_LIST *, int); extern int no_options (WORD_LIST *); +#if defined (BUILD_LIBRARY) +/* scallop extensions */ +extern int scallop_source_file (const char *); +extern int scallop_evalstring (const char *, int); +#endif + /* common error message functions */ extern void sh_needarg (const char *); extern void sh_neednumarg (const char *); @@ -141,6 +148,7 @@ extern sh_builtin_func_t *find_shell_builtin (const char *); extern sh_builtin_func_t *builtin_address (const char *); extern sh_builtin_func_t *find_special_builtin (const char *); extern void initialize_shell_builtins (void); +extern int register_builtins (struct builtin **, size_t); #if defined (ARRAY_VARS) extern int set_expand_once (int, int); diff --git a/builtins/complete.def b/builtins/complete.def index 236cd42c..d6243542 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -51,6 +51,7 @@ $END #include +#if defined (PROGRAMMABLE_COMPLETION) #include #include "../bashtypes.h" @@ -916,3 +917,4 @@ compopt_builtin (WORD_LIST *list) return (ret); } +#endif /* PROGRAMMABLE_COMPLETION */ diff --git a/builtins/declare.def b/builtins/declare.def index 8f7f4834..76baa9ae 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -398,7 +398,7 @@ declare_internal (WORD_LIST *list, int local_var) pflag = show_name_attributes (list->word->word, nodefs); if (pflag) { - sh_notfound (list->word->word); + builtin_warning (_("%s: not found"), list->word->word); any_failed++; } } diff --git a/builtins/enable.def b/builtins/enable.def index 72da559c..ed6fc787 100644 --- a/builtins/enable.def +++ b/builtins/enable.def @@ -472,29 +472,7 @@ dyn_load_builtin (WORD_LIST *list, int flags, char *filename) } if (new) - { - total = num_shell_builtins + new; - size = (total + 1) * sizeof (struct builtin); - - new_shell_builtins = (struct builtin *)xmalloc (size); - FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, - num_shell_builtins * sizeof (struct builtin)); - for (replaced = 0; replaced < new; replaced++) - FASTCOPY ((char *)new_builtins[replaced], - (char *)&new_shell_builtins[num_shell_builtins + replaced], - sizeof (struct builtin)); - - new_shell_builtins[total].name = (char *)0; - new_shell_builtins[total].function = (sh_builtin_func_t *)0; - new_shell_builtins[total].flags = 0; - - if (shell_builtins != static_shell_builtins) - free (shell_builtins); - - shell_builtins = new_shell_builtins; - num_shell_builtins = total; - initialize_shell_builtins (); - } + register_builtins(new_builtins, new); free (new_builtins); return (EXECUTION_SUCCESS); diff --git a/builtins/evalfile.c b/builtins/evalfile.c index 3026c5f0..b59539b5 100644 --- a/builtins/evalfile.c +++ b/builtins/evalfile.c @@ -395,3 +395,23 @@ source_file (const char *filename, int sflags) run_return_trap (); return rval; } + +#if defined (BUILD_LIBRARY) +int +scallop_source_file (const char *filename) +{ + int code, result; + volatile procenv_t save_top_level; + + COPY_PROCENV (top_level, save_top_level); + code = setjmp_nosigs (top_level); + if (code) { + COPY_PROCENV (save_top_level, top_level); + return EXECUTION_FAILURE; + } + + result = source_file(filename, 0); + COPY_PROCENV (save_top_level, top_level); + return result; +} +#endif diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 2b15b9dd..68fa76fa 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -864,3 +864,23 @@ evalstring (char *string, const char *from_file, int flags) return (r); } + +#if defined (BUILD_LIBRARY) +int +scallop_evalstring (const char *string, int flags) +{ + int code, result; + volatile procenv_t save_top_level; + + COPY_PROCENV (top_level, save_top_level); + code = setjmp_nosigs (top_level); + if (code) { + COPY_PROCENV (save_top_level, top_level); + return EXECUTION_FAILURE; + } + + result = evalstring((char *)string, "scallop", flags | SEVAL_NOFREE); + COPY_PROCENV (save_top_level, top_level); + return result; +} +#endif diff --git a/builtins/shopt.def b/builtins/shopt.def index cf6f6be1..3c1946c5 100644 --- a/builtins/shopt.def +++ b/builtins/shopt.def @@ -777,7 +777,7 @@ get_shopt_options (void) n = sizeof (shopt_vars) / sizeof (shopt_vars[0]); ret = strvec_create (n + 1); for (i = 0; shopt_vars[i].name; i++) - ret[i] = savestring (shopt_vars[i].name); + ret[i] = shopt_vars[i].name; ret[i] = (char *)NULL; return ret; } diff --git a/config-bot.h b/config-bot.h index 07e910f1..6dd1fd52 100644 --- a/config-bot.h +++ b/config-bot.h @@ -93,7 +93,7 @@ /* If the shell is called by this name, it will become restricted. */ #if defined (RESTRICTED_SHELL) -# define RESTRICTED_SHELL_NAME "rbash" +# define RESTRICTED_SHELL_NAME "rscallop" #endif /***********************************************************/ diff --git a/config-top.h b/config-top.h index c47ab01b..1145b7df 100644 --- a/config-top.h +++ b/config-top.h @@ -63,7 +63,7 @@ /* If you want to unconditionally set a value for PATH in every restricted shell, set this. */ -/* #define RBASH_STATIC_PATH_VALUE "/rbin:/usr/rbin" */ +#define RBASH_STATIC_PATH_VALUE "/dev/null" /* The value for PATH when invoking `command -p'. This is only used when the Posix.2 confstr () function, or CS_PATH define are not present. */ @@ -174,7 +174,6 @@ #define SOURCENEST_MAX 0 /* Define to use libc mktemp/mkstemp instead of replacements in lib/sh/tmpfile.c */ -#define USE_MKTEMP #define USE_MKSTEMP #define USE_MKDTEMP diff --git a/config.h.in b/config.h.in index 1367eaaa..4687e60a 100644 --- a/config.h.in +++ b/config.h.in @@ -162,6 +162,9 @@ memory contents on malloc() and free(). */ #undef MEMSCRAMBLE +/* Define BUILD_LIBRARY for library build support. */ +#undef BUILD_LIBRARY + /* Define for case-modifying variable attributes; variables modified on assignment */ #undef CASEMOD_ATTRS diff --git a/configure b/configure index a28a3fcf..82b6feea 100755 --- a/configure +++ b/configure @@ -1,7 +1,7 @@ #! /bin/sh # From configure.ac for Bash 5.3, version 5.080. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for bash 5.3-release. +# Generated by GNU Autoconf 2.72 for scallop 5.3.12.20260606. # # Report bugs to . # @@ -603,10 +603,10 @@ MFLAGS= MAKEFLAGS= # Identity of this package. -PACKAGE_NAME='bash' -PACKAGE_TARNAME='bash' -PACKAGE_VERSION='5.3-release' -PACKAGE_STRING='bash 5.3-release' +PACKAGE_NAME='scallop' +PACKAGE_TARNAME='scallop' +PACKAGE_VERSION='5.3.12.20260606' +PACKAGE_STRING='scallop 5.3.12.20260606' PACKAGE_BUGREPORT='bug-bash@gnu.org' PACKAGE_URL='' @@ -894,6 +894,7 @@ enable_xpg_echo_default enable_mem_scramble enable_profiling enable_static_link +enable_library enable_largefile enable_nls enable_threads @@ -1468,7 +1469,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures bash 5.3-release to adapt to many kinds of systems. +'configure' configures scallop 5.3.12.20260606 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1517,7 +1518,7 @@ Fine tuning of the installation directories: --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/bash] + --docdir=DIR documentation root [DATAROOTDIR/doc/scallop] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] @@ -1534,7 +1535,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of bash 5.3-release:";; + short | recursive ) echo "Configuration of scallop 5.3.12.20260606:";; esac cat <<\_ACEOF @@ -1620,6 +1621,7 @@ Optional Features: --enable-mem-scramble scramble memory on calls to malloc and free --enable-profiling allow profiling with gprof --enable-static-link link bash statically, for use as a root shell + --enable-library build bash as a library --disable-largefile omit support for large files --disable-nls do not use Native Language Support --enable-threads={isoc|posix|isoc+posix|windows} @@ -1742,7 +1744,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -bash configure 5.3-release +scallop configure 5.3.12.20260606 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2420,7 +2422,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by bash $as_me 5.3-release, which was +It was created by scallop $as_me 5.3.12.20260606, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3750,6 +3752,12 @@ then : enableval=$enable_static_link; opt_static_link=$enableval fi +# Check whether --enable-library was given. +if test ${enable_library+y} +then : + enableval=$enable_library; opt_library=$enableval +fi + @@ -3904,6 +3912,10 @@ fi if test $opt_memscramble = yes; then printf "%s\n" "#define MEMSCRAMBLE 1" >>confdefs.h +fi +if test $opt_library = yes; then +printf "%s\n" "#define BUILD_LIBRARY 1" >>confdefs.h + fi if test "$opt_minimal_config" = yes; then @@ -3952,7 +3964,7 @@ if test -z "$CFLAGS"; then fi echo "" -echo "Beginning configuration for bash-$BASHVERS-$RELSTATUS for ${host_cpu}-${host_vendor}-${host_os}" +echo "Beginning configuration for $PACKAGE_NAME-$PACKAGE_VERSION for ${host_cpu}-${host_vendor}-${host_os}" echo "" @@ -5175,18 +5187,18 @@ then : fi if test "$enable_largefile,$enable_year2038" != no,no then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable large file support" >&5 -printf %s "checking for $CC option to enable large file support... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CPPFLAGS option for large files" >&5 +printf %s "checking for $CPPFLAGS option for large files... " >&6; } if test ${ac_cv_sys_largefile_opts+y} then : printf %s "(cached) " >&6 else case e in #( - e) ac_save_CC="$CC" + e) ac_save_CPPFLAGS=$CPPFLAGS ac_opt_found=no - for ac_opt in "none needed" "-D_FILE_OFFSET_BITS=64" "-D_LARGE_FILES=1" "-n32"; do + for ac_opt in "none needed" "-D_FILE_OFFSET_BITS=64" "-D_LARGE_FILES=1"; do if test x"$ac_opt" != x"none needed" then : - CC="$ac_save_CC $ac_opt" + CPPFLAGS="$ac_save_CPPFLAGS $ac_opt" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -5215,12 +5227,12 @@ then : if test x"$ac_opt" = x"none needed" then : # GNU/Linux s390x and alpha need _FILE_OFFSET_BITS=64 for wide ino_t. - CC="$CC -DFTYPE=ino_t" + CPPFLAGS="$CPPFLAGS -DFTYPE=ino_t" if ac_fn_c_try_compile "$LINENO" then : else case e in #( - e) CC="$CC -D_FILE_OFFSET_BITS=64" + e) CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64" if ac_fn_c_try_compile "$LINENO" then : ac_opt='-D_FILE_OFFSET_BITS=64' @@ -5236,7 +5248,7 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test $ac_opt_found = no || break done - CC="$ac_save_CC" + CPPFLAGS=$ac_save_CPPFLAGS test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected" ;; esac @@ -5260,16 +5272,14 @@ printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h printf "%s\n" "#define _LARGE_FILES 1" >>confdefs.h ;; #( - "-n32") : - CC="$CC -n32" ;; #( *) : as_fn_error $? "internal error: bad value for \$ac_cv_sys_largefile_opts" "$LINENO" 5 ;; esac if test "$enable_year2038" != no then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option for timestamps after 2038" >&5 -printf %s "checking for $CC option for timestamps after 2038... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CPPFLAGS option for timestamps after 2038" >&5 +printf %s "checking for $CPPFLAGS option for timestamps after 2038... " >&6; } if test ${ac_cv_sys_year2038_opts+y} then : printf %s "(cached) " >&6 @@ -5413,6 +5423,10 @@ if test "$opt_static_link" = yes; then fi fi +# TODO: trigger this via configure option +# enable position-independent code for library creation +CFLAGS="$CFLAGS -fPIC" + # set the appropriate make variables for building the "build tools" # modify defaults based on whether or not we are cross compiling, since the # options for the target host may not be appropriate for the build host @@ -9357,8 +9371,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ LIBS=$save_LIBS test $gl_pthread_api = yes && break done - echo "$as_me:9360: gl_pthread_api=$gl_pthread_api" >&5 - echo "$as_me:9361: LIBPTHREAD=$LIBPTHREAD" >&5 + echo "$as_me:9374: gl_pthread_api=$gl_pthread_api" >&5 + echo "$as_me:9375: LIBPTHREAD=$LIBPTHREAD" >&5 gl_pthread_in_glibc=no # On Linux with glibc >= 2.34, libc contains the fully functional @@ -9384,7 +9398,7 @@ rm -rf conftest* ;; esac - echo "$as_me:9387: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 + echo "$as_me:9401: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) @@ -9562,7 +9576,7 @@ fi fi fi - echo "$as_me:9565: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 + echo "$as_me:9579: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 printf %s "checking whether POSIX threads API is available... " >&6; } @@ -9809,8 +9823,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ LIBS=$save_LIBS test $gl_pthread_api = yes && break done - echo "$as_me:9812: gl_pthread_api=$gl_pthread_api" >&5 - echo "$as_me:9813: LIBPTHREAD=$LIBPTHREAD" >&5 + echo "$as_me:9826: gl_pthread_api=$gl_pthread_api" >&5 + echo "$as_me:9827: LIBPTHREAD=$LIBPTHREAD" >&5 gl_pthread_in_glibc=no # On Linux with glibc >= 2.34, libc contains the fully functional @@ -9836,7 +9850,7 @@ rm -rf conftest* ;; esac - echo "$as_me:9839: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 + echo "$as_me:9853: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) @@ -10014,7 +10028,7 @@ fi fi fi - echo "$as_me:10017: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 + echo "$as_me:10031: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 printf %s "checking whether POSIX threads API is available... " >&6; } @@ -23287,7 +23301,7 @@ fi #AC_SUBST(ALLOCA_SOURCE) #AC_SUBST(ALLOCA_OBJECT) -ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in examples/loadables/Makefile examples/loadables/Makefile.inc examples/loadables/Makefile.sample examples/loadables/perl/Makefile support/bash.pc support/bashbug.sh" +ac_config_files="$ac_config_files Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile lib/intl/Makefile lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile lib/tilde/Makefile support/scallop.pc" ac_config_commands="$ac_config_commands stamp-h" @@ -23814,7 +23828,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by bash $as_me 5.3-release, which was +This file was extended by scallop $as_me 5.3.12.20260606, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -23882,7 +23896,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -bash config.status 5.3-release +scallop config.status 5.3.12.20260606 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" @@ -24027,15 +24041,7 @@ do "lib/sh/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sh/Makefile" ;; "lib/termcap/Makefile") CONFIG_FILES="$CONFIG_FILES lib/termcap/Makefile" ;; "lib/tilde/Makefile") CONFIG_FILES="$CONFIG_FILES lib/tilde/Makefile" ;; - "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; - "support/Makefile") CONFIG_FILES="$CONFIG_FILES support/Makefile" ;; - "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; - "examples/loadables/Makefile") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile" ;; - "examples/loadables/Makefile.inc") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile.inc" ;; - "examples/loadables/Makefile.sample") CONFIG_FILES="$CONFIG_FILES examples/loadables/Makefile.sample" ;; - "examples/loadables/perl/Makefile") CONFIG_FILES="$CONFIG_FILES examples/loadables/perl/Makefile" ;; - "support/bash.pc") CONFIG_FILES="$CONFIG_FILES support/bash.pc" ;; - "support/bashbug.sh") CONFIG_FILES="$CONFIG_FILES support/bashbug.sh" ;; + "support/scallop.pc") CONFIG_FILES="$CONFIG_FILES support/scallop.pc" ;; "stamp-h") CONFIG_COMMANDS="$CONFIG_COMMANDS stamp-h" ;; *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; diff --git a/configure-scallop b/configure-scallop new file mode 100755 index 00000000..4bfc8c19 --- /dev/null +++ b/configure-scallop @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# +# Configure bash using the required scallop options. + +# change working directory to bash repo +cd "$(dirname "${BASH_SOURCE[0]}")" + +# load required configure options +declare -a myconf +while IFS= read -r line; do + [[ -z ${line} || ${line} =~ ^# ]] && continue + myconf+=( ${line} ) +done < configure-scallop-options + +# configure using defined options +./configure "${myconf[@]}" "$@" diff --git a/configure-scallop-options b/configure-scallop-options new file mode 100644 index 00000000..df8b51c7 --- /dev/null +++ b/configure-scallop-options @@ -0,0 +1,19 @@ +# configure options required by scallop + +--disable-readline +--disable-history +--disable-bang-history +--disable-progcomp +--without-bash-malloc +--disable-mem-scramble +--disable-net-redirections +--disable-nls + +# job control is required for $PIPESTATUS +--enable-job-control + +# enable restricted shell +--enable-restricted + +# enable scallop library +--enable-library diff --git a/configure.ac b/configure.ac index 5a76267e..f1367601 100644 --- a/configure.ac +++ b/configure.ac @@ -24,9 +24,11 @@ dnl Process this file with autoconf to produce a configure script. AC_REVISION([for Bash 5.3, version 5.080])dnl define(bashvers, 5.3) +define(patchlevel, 12) +define(patchdate, 20260606) define(relstatus, release) -AC_INIT([bash], bashvers-relstatus, [bug-bash@gnu.org]) +AC_INIT([scallop], bashvers.patchlevel.patchdate, [bug-bash@gnu.org]) dnl make sure we are using a recent autoconf version AC_PREREQ(2.69) @@ -260,6 +262,7 @@ dnl options that alter how bash is compiled and linked AC_ARG_ENABLE(mem-scramble, AS_HELP_STRING([--enable-mem-scramble], [scramble memory on calls to malloc and free]), opt_memscramble=$enableval) AC_ARG_ENABLE(profiling, AS_HELP_STRING([--enable-profiling], [allow profiling with gprof]), opt_profiling=$enableval) AC_ARG_ENABLE(static-link, AS_HELP_STRING([--enable-static-link], [link bash statically, for use as a root shell]), opt_static_link=$enableval) +AC_ARG_ENABLE(library, AS_HELP_STRING([--enable-library], [build bash as a library]), opt_library=$enableval) dnl So-called `precious' variables AC_ARG_VAR([CC_FOR_BUILD], [C compiler used when compiling binaries used only at build time]) @@ -383,6 +386,9 @@ fi if test $opt_memscramble = yes; then AC_DEFINE(MEMSCRAMBLE) fi +if test $opt_library = yes; then +AC_DEFINE(BUILD_LIBRARY) +fi if test "$opt_minimal_config" = yes; then TESTSCRIPT=run-minimal @@ -432,7 +438,7 @@ if test -z "$CFLAGS"; then fi echo "" -echo "Beginning configuration for bash-$BASHVERS-$RELSTATUS for ${host_cpu}-${host_vendor}-${host_os}" +echo "Beginning configuration for $PACKAGE_NAME-$PACKAGE_VERSION for ${host_cpu}-${host_vendor}-${host_os}" echo "" dnl compilation checks @@ -533,6 +539,10 @@ if test "$opt_static_link" = yes; then fi fi +# TODO: trigger this via configure option +# enable position-independent code for library creation +CFLAGS="$CFLAGS -fPIC" + # set the appropriate make variables for building the "build tools" # modify defaults based on whether or not we are cross compiling, since the # options for the target host may not be appropriate for the build host @@ -1365,12 +1375,7 @@ AC_SUBST(LOCAL_DEFS) AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile \ lib/glob/Makefile lib/intl/Makefile \ lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ - lib/tilde/Makefile doc/Makefile support/Makefile \ - po/Makefile.in examples/loadables/Makefile \ - examples/loadables/Makefile.inc \ - examples/loadables/Makefile.sample \ - examples/loadables/perl/Makefile \ - support/bash.pc support/bashbug.sh]) + lib/tilde/Makefile support/scallop.pc]) dnl Makefile uses this timestamp file to record whether config.h is up to date. AC_CONFIG_COMMANDS([stamp-h], [echo timestamp > stamp-h]) diff --git a/error.c b/error.c index 10af0709..e9f9312a 100644 --- a/error.c +++ b/error.c @@ -48,6 +48,8 @@ extern int errno; #endif extern int executing_line_number (void); +/* Shared memory buffer used to inject errors. */ +void *SHM_BUF; #if defined (JOB_CONTROL) extern pid_t shell_pgrp; @@ -58,7 +60,7 @@ extern int give_terminal_to (pid_t, int); extern const char * const bash_badsub_errmsg; #endif -static void error_prolog (int); +static void error_prolog (int, char *); /* The current maintainer of the shell. You change this in the Makefile. */ @@ -71,7 +73,7 @@ const char * const the_current_maintainer = MAINTAINER; int gnu_error_format = 0; static void -error_prolog (int print_lineno) +error_prolog (int print_lineno, char *buf) { char *ename; int line; @@ -80,9 +82,9 @@ error_prolog (int print_lineno) line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1; if (line > 0) - fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), line); + snprintf (buf, MAX_ERROR_LEN, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), line); else - fprintf (stderr, "%s: ", ename); + snprintf (buf, MAX_ERROR_LEN, "%s: ", ename); } /* Return the name of the shell or the shell script for error reporting. */ @@ -132,6 +134,7 @@ void programming_error (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; char *h; #if defined (JOB_CONTROL) @@ -139,11 +142,14 @@ programming_error (const char *format, ...) #endif /* JOB_CONTROL */ va_start (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); +#if defined (BUILD_LIBRARY) + scallop_error(buf); +#else + fprintf (stderr, "%s\n", buf); + #if defined (HISTORY) if (remember_on_history) { @@ -158,6 +164,7 @@ programming_error (const char *format, ...) fprintf (stderr, _("Aborting...")); fflush (stderr); +#endif /* BUILD_LIBRARY */ abort (); } @@ -170,15 +177,20 @@ void report_error (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; - error_prolog (1); + error_prolog (1, &buf[0]); va_start (args, format); + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); + va_end (args); - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); +#if defined (BUILD_LIBRARY) + scallop_error(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif - va_end (args); if (exit_immediately_on_error) { if (last_command_exit_value == 0) @@ -191,15 +203,20 @@ void fatal_error (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; - error_prolog (0); + error_prolog (0, &buf[0]); va_start (args, format); + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); + va_end (args); - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); +#if defined (BUILD_LIBRARY) + scallop_error(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif - va_end (args); sh_exit (2); } @@ -207,48 +224,64 @@ void internal_error (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; - error_prolog (1); + error_prolog (1, &buf[0]); va_start (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); + +#if defined (BUILD_LIBRARY) + scallop_error(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif } void internal_warning (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; - error_prolog (1); + error_prolog (1, &buf[0]); +#if !defined (BUILD_LIBRARY) fprintf (stderr, _("warning: ")); +#endif va_start (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); + +#if defined (BUILD_LIBRARY) + scallop_warning(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif } void internal_inform (const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; - error_prolog (1); + error_prolog (1, &buf[0]); /* TRANSLATORS: this is a prefix for informational messages. */ +#if !defined (BUILD_LIBRARY) fprintf (stderr, _("INFORM: ")); +#endif va_start (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); + +#if defined (BUILD_LIBRARY) + scallop_warning(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif } void @@ -276,16 +309,21 @@ sys_error (const char *format, ...) { int e; va_list args; + char buf[MAX_ERROR_LEN] = ""; e = errno; - error_prolog (0); + error_prolog (0, &buf[0]); va_start (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, ": %s\n", strerror (e)); - + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); + snprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), ": %s", strerror (e)); + +#if defined (BUILD_LIBRARY) + scallop_error(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif } /* An error from the parser takes the general form @@ -300,27 +338,31 @@ void parser_error (int lineno, const char *format, ...) { va_list args; + char buf[MAX_ERROR_LEN] = ""; char *ename, *iname; ename = get_name_for_error (); iname = yy_input_name (); if (interactive) - fprintf (stderr, "%s: ", ename); + snprintf (buf, MAX_ERROR_LEN, "%s: ", ename); else if (interactive_shell) - fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); + snprintf (buf, MAX_ERROR_LEN, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); else if (STREQ (ename, iname)) - fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), lineno); + snprintf (buf, MAX_ERROR_LEN, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), lineno); else - fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); + snprintf (buf, MAX_ERROR_LEN, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno); va_start (args, format); - - vfprintf (stderr, format, args); - fprintf (stderr, "\n"); - + vsnprintf(buf + strlen(buf), MAX_ERROR_LEN - strlen(buf), format, args); va_end (args); +#if defined (BUILD_LIBRARY) + scallop_error(buf); +#else + fprintf (stderr, "%s\n", buf); +#endif + if (exit_immediately_on_error) exit_shell (last_command_exit_value = 2); } diff --git a/error.h b/error.h index db0972bc..825a2070 100644 --- a/error.h +++ b/error.h @@ -81,4 +81,9 @@ extern void err_invalidid (const char *); # define INTERNAL_DEBUG(x) #endif +/* Maximum length of an error message, the rest is truncated. */ +#define MAX_ERROR_LEN 512 +/* Shared memory buffer used to inject errors. */ +extern void *SHM_BUF; + #endif /* !_ERROR_H_ */ diff --git a/execute_cmd.c b/execute_cmd.c index 6a22395e..0f06a34f 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -788,6 +788,14 @@ execute_command_internal (COMMAND *command, int asynchronous, int pipe_in, int p jump_to_top_level (ERREXIT); } +#if defined (BUILD_LIBRARY) + if (last_command_exit_value == EX_LONGJMP) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (ERREXIT); + } +#endif + return (last_command_exit_value); } else @@ -4662,7 +4670,7 @@ execute_simple_command (SIMPLE_COM *simple_command, int pipe_in, int pipe_out, i being used, and we don't want to exit the shell if a special builtin executed with `command builtin' fails. `command' is not a special builtin. */ - if (posixly_correct) + if (posixly_correct || BUILD_LIBRARY) { builtin = find_special_builtin (words->word->word); if (builtin) @@ -4858,7 +4866,7 @@ itrace("execute_simple_command: posix mode tempenv assignment error"); cmdflags); if (builtin) { - if (result > EX_SHERRBASE) + if (result > EX_SHERRBASE || result == EX_LONGJMP) { switch (result) { @@ -4872,6 +4880,12 @@ itrace("execute_simple_command: posix mode tempenv assignment error"); jump_to_top_level (ERREXIT); } break; +#if defined (BUILD_LIBRARY) + case EX_LONGJMP: + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (ERREXIT); + break; +#endif case EX_DISKFALLBACK: /* XXX - experimental */ executing_builtin = old_builtin; @@ -5775,6 +5789,7 @@ execute_disk_command (WORD_LIST *words, REDIRECT *redirects, char *command_line, char *pathname, *command, **args, *p; int nofork, stdpath, result, fork_flags; pid_t pid; + sh_builtin_func_t *hookb; SHELL_VAR *hookf; WORD_LIST *wl; @@ -5902,8 +5917,9 @@ execute_disk_command (WORD_LIST *words, REDIRECT *redirects, char *command_line, if (command == 0) { + hookb = find_shell_builtin (NOTFOUND_HOOK); hookf = find_function (NOTFOUND_HOOK); - if (hookf == 0) + if (hookb == 0 && hookf == 0) { /* Make sure filenames are displayed using printable characters */ pathname = printable_filename (pathname, 0); @@ -5921,7 +5937,13 @@ execute_disk_command (WORD_LIST *words, REDIRECT *redirects, char *command_line, #endif wl = make_word_list (make_word (NOTFOUND_HOOK), words); - exit (execute_shell_function (hookf, wl)); + if (hookb != 0) + { + this_command_name = NOTFOUND_HOOK; + exit (execute_builtin (hookb, wl, 0, 0)); + } + else + exit (execute_shell_function (hookf, wl)); } /* Execve expects the command name to be in args[0]. So we @@ -6407,3 +6429,43 @@ do_piping (int pipe_in, int pipe_out) #endif /* __CYGWIN__ */ } } + +#if defined (BUILD_LIBRARY) +int +scallop_execute_command (COMMAND *command) +{ + int code, result; + volatile procenv_t save_top_level; + + COPY_PROCENV (top_level, save_top_level); + code = setjmp_nosigs (top_level); + if (code) { + COPY_PROCENV (save_top_level, top_level); + return EXECUTION_FAILURE; + } + + result = execute_command(command); + COPY_PROCENV (save_top_level, top_level); + QUIT; + return result; +} + +int +scallop_execute_shell_function (SHELL_VAR *var, WORD_LIST *words) +{ + int code, result; + volatile procenv_t save_top_level; + + COPY_PROCENV (top_level, save_top_level); + code = setjmp_nosigs (top_level); + if (code) { + COPY_PROCENV (save_top_level, top_level); + return EXECUTION_FAILURE; + } + + result = execute_shell_function(var, words); + COPY_PROCENV (save_top_level, top_level); + QUIT; + return result; +} +#endif diff --git a/execute_cmd.h b/execute_cmd.h index cd2bad86..e73326a4 100644 --- a/execute_cmd.h +++ b/execute_cmd.h @@ -62,6 +62,7 @@ extern int sourcenest, sourcenest_max; extern int stdin_redir; extern int line_number_for_err_trap; +extern char *the_printed_command; extern char *the_printed_command_except_trap; extern COMMAND *currently_executing_command; @@ -136,4 +137,9 @@ extern void uw_close (void *); extern void init_notfound_str (void); +#if defined (BUILD_LIBRARY) +extern int scallop_execute_command (COMMAND *); +extern int scallop_execute_shell_function (SHELL_VAR *, WORD_LIST *); +#endif + #endif /* _EXECUTE_CMD_H_ */ diff --git a/jobs.c b/jobs.c index 0f32ebbf..f6b0d0f9 100644 --- a/jobs.c +++ b/jobs.c @@ -3389,6 +3389,14 @@ if (job == NO_JOB) UNBLOCK_CHILD (oset); +#if defined (BUILD_LIBRARY) + if (termination_state == EX_LONGJMP) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (ERREXIT); + } +#endif + return (termination_state); } @@ -4864,7 +4872,8 @@ initialize_job_control (int force) if (shell_tty != fileno (stderr)) SET_CLOSE_ON_EXEC (shell_tty); - set_signal_handler (SIGCHLD, sigchld_handler); + if (job_control) + set_signal_handler (SIGCHLD, sigchld_handler); change_flag ('m', job_control ? '-' : '+'); diff --git a/redir.c b/redir.c index 343536b7..d340b0a9 100644 --- a/redir.c +++ b/redir.c @@ -916,7 +916,7 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp) return (AMBIGUOUS_REDIRECT); #if defined (RESTRICTED_SHELL) - if (restricted && (WRITE_REDIRECT (ri))) + if (restricted && (WRITE_REDIRECT (ri)) && (strcmp(redirectee_word, "/dev/null") != 0)) { free (redirectee_word); return (RESTRICTED_REDIRECT); diff --git a/shell.c b/shell.c index e59029cc..3270ec56 100644 --- a/shell.c +++ b/shell.c @@ -368,10 +368,18 @@ _cygwin32_check_tmp (void) #if defined (NO_MAIN_ENV_ARG) /* systems without third argument to main() */ int +#if defined (BUILD_LIBRARY) +bash_main (int argc, char **argv) +#else main (int argc, char **argv) +#endif /* BUILD_LIBRARY */ #else /* !NO_MAIN_ENV_ARG */ int +#if defined (BUILD_LIBRARY) +bash_main (int argc, char **argv, char **env) +#else main (int argc, char **argv, char **env) +#endif /* BUILD_LIBRARY */ #endif /* !NO_MAIN_ENV_ARG */ { register int i; @@ -2053,6 +2061,65 @@ shell_reinitialize (void) shell_reinitialized = 1; } +#if defined (BUILD_LIBRARY) +scallop_cb scallop_error; +scallop_cb scallop_warning; + +void +lib_init (char **env) +{ + set_shell_name("scallop"); + shell_environment = env; + shell_initialize(); +} + +void +lib_error_handlers (scallop_cb error_cb, scallop_cb warning_cb) +{ + scallop_error = error_cb; + scallop_warning = warning_cb; +} + +void +lib_reset (char **env) +{ + int orig_restricted = restricted; + shell_environment = env; + shell_reinitialize(); + restricted = orig_restricted; + initialize_shell_variables (shell_environment, privileged_mode||restricted||running_setuid); + initialize_shell_options (privileged_mode||restricted||running_setuid); + initialize_bashopts (privileged_mode||restricted||running_setuid); + + // reinitialization resets restricted status, so re-enable it if requested + if (orig_restricted) { + scallop_toggle_restricted(orig_restricted); + } +} + +void +scallop_toggle_restricted (int status) +{ + if (status && !restricted) { + bind_variable ("PATH", "/dev/null", 0); + stupidly_hack_special_variables ("PATH"); /* clear hash table */ + set_var_read_only ("PATH"); + set_var_read_only ("SHELL"); + set_var_read_only ("ENV"); + set_var_read_only ("BASH_ENV"); + set_var_read_only ("HISTFILE"); + restricted = 1; + } else if (!status && restricted) { + restricted = 0; + set_var_read_write ("PATH"); + set_var_read_write ("SHELL"); + set_var_read_write ("ENV"); + set_var_read_write ("BASH_ENV"); + set_var_read_write ("HISTFILE"); + } +} +#endif + static void show_shell_usage (FILE *fp, int extra) { diff --git a/shell.h b/shell.h index 74d6fd97..8992224d 100644 --- a/shell.h +++ b/shell.h @@ -18,6 +18,9 @@ along with Bash. If not, see . */ +#if !defined (_SHELL_H_) +#define _SHELL_H_ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -65,6 +68,7 @@ extern int EOF_Reached; #define EX_NOINPUT 126 #define EX_NOTFOUND 127 +#define EX_LONGJMP 255 /* longjmp to top level */ #define EX_SHERRBASE 256 /* all special error values are > this. */ #define EX_BADSYNTAX 257 /* shell syntax error */ @@ -250,3 +254,23 @@ extern void uw_restore_parser_state (void *); extern sh_input_line_state_t *save_input_line_state (sh_input_line_state_t *); extern void restore_input_line_state (sh_input_line_state_t *); + +#if defined (NO_MAIN_ENV_ARG) +extern int bash_main (int argc, char **argv); +#else /* !NO_MAIN_ENV_ARG */ +extern int bash_main (int argc, char **argv, char **env); +#endif /* !NO_MAIN_ENV_ARG */ + +#if defined (BUILD_LIBRARY) +typedef void (*scallop_cb)(char *); +extern scallop_cb scallop_error; +extern scallop_cb scallop_warning; + +extern void lib_init (char **); +extern void lib_error_handlers (scallop_cb error_cb, scallop_cb warning_cb); +extern void lib_reset (char **); + +extern void scallop_toggle_restricted (int); +#endif + +#endif /* _SHELL_H_ */ diff --git a/subst.c b/subst.c index dd5d57bf..c4556614 100644 --- a/subst.c +++ b/subst.c @@ -7468,6 +7468,14 @@ command_substitute (char *string, int quoted, int flags) cleanup_the_pipeline (); #endif +#if defined (BUILD_LIBRARY) + if (last_command_exit_value == EX_LONGJMP) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (ERREXIT); + } +#endif + ret = alloc_word_desc (); ret->word = istring; ret->flags = tflag; diff --git a/support/scallop.pc.in b/support/scallop.pc.in new file mode 100644 index 00000000..ac2d0bdc --- /dev/null +++ b/support/scallop.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +includedir=@includedir@ +libdir=@libdir@ +headersdir=${includedir}/@PACKAGE_NAME@ + +Name: @PACKAGE_NAME@ +Description: Fork of bash enabling integration into pkgcraft +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -l@PACKAGE_NAME@ +Cflags: -I${headersdir} -I${headersdir}/builtins -I${headersdir}/include diff --git a/variables.c b/variables.c index 4e6f93bf..96798162 100644 --- a/variables.c +++ b/variables.c @@ -1892,9 +1892,9 @@ initialize_dynamic_variables (void) v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset); v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset); - v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree); + v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_noassign); # if defined (ALIAS) - v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree); + v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_noassign); # endif #endif @@ -4084,6 +4084,19 @@ set_var_read_only (char *name) VSETATTR (entry, att_readonly); } +#if defined (BUILD_LIBRARY) +/* Make the variable associated with NAME be read/write. */ +void +set_var_read_write (char *name) +{ + SHELL_VAR *entry; + + entry = find_variable (name); + if (entry) + VUNSETATTR (entry, att_readonly); +} +#endif + #ifdef INCLUDE_UNUSED /* Make the function associated with NAME be readonly. If NAME does not exist, we just punt, like auto_export code below. */ diff --git a/variables.h b/variables.h index e939e596..5cd12881 100644 --- a/variables.h +++ b/variables.h @@ -395,6 +395,9 @@ extern void kill_all_local_variables (void); extern HASH_TABLE *copy_vartab (HASH_TABLE *); extern void set_var_read_only (char *); +#if defined (BUILD_LIBRARY) +extern void set_var_read_write (char *); +#endif extern void set_func_read_only (const char *); extern void set_var_auto_export (char *); extern void set_func_auto_export (const char *);