diff --git a/.gitignore b/.gitignore index 72c87827..626ce7fa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,8 @@ /src/server/autom4te.cache /src/client/autom4te.cache /src/fe/autom4te.cache - +.vscode +.idea/ tags #Need if someone does an in-source configure/build @@ -34,5 +35,3 @@ run_driver run_driver_rm preload_file_list build - -.idea/ diff --git a/config.h.in b/config.h.in index 8c7a94db..a2afe8a8 100644 --- a/config.h.in +++ b/config.h.in @@ -40,6 +40,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H +/* ld.so exports the _dl_argv variable */ +#undef HAVE_DL_ARGV + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H diff --git a/configure b/configure index e9a4f95a..0a52a68f 100755 --- a/configure +++ b/configure @@ -17290,6 +17290,33 @@ _ACEOF fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking wheter ld.so has the _dl_argv variable" >&5 +$as_echo_n "checking wheter ld.so has the _dl_argv variable... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char **_dl_argv; +int +main () +{ +(void) _dl_argv; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + HAVE_DL_ARGV="true";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "x$HAVE_DL_ARGV" == "xtrue"; then + +$as_echo "#define HAVE_DL_ARGV 1" >>confdefs.h + +fi #Usage logging diff --git a/configure.common.ac b/configure.common.ac index e8d311f4..4e6141c0 100644 --- a/configure.common.ac +++ b/configure.common.ac @@ -322,7 +322,13 @@ if test "x$HAVE_NUMA" == "xtrue"; then AC_DEFINE_UNQUOTED([NUMA_EXCLUDES], "[$NUMA_EXCLUDES_VAL]", [Exclusions for numa optimization]) fi - +AC_MSG_CHECKING([wheter ld.so has the _dl_argv variable]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([extern char **_dl_argv;], [(void) _dl_argv;])], + [HAVE_DL_ARGV="true";AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) +if test "x$HAVE_DL_ARGV" == "xtrue"; then + AC_DEFINE([HAVE_DL_ARGV], [1], [ld.so exports the _dl_argv variable]) +fi + #Usage logging AC_ARG_WITH(usage-logging, [AS_HELP_STRING([--with-usage-logging=FILE],[File for writing usage logs])], diff --git a/src/client/auditclient/auditclient.c b/src/client/auditclient/auditclient.c index db7d5574..cdaacfc5 100644 --- a/src/client/auditclient/auditclient.c +++ b/src/client/auditclient/auditclient.c @@ -54,23 +54,8 @@ unsigned int spindle_la_objopen(struct link_map *map, Lmid_t lmid, uintptr_t *co { (void)lmid; (void)cookie; - char buffer[4096]; - char *exe_name, *exe_name2; - restore_pathpatch(); patch_on_linkactivity(map); - memset(buffer, 0, sizeof(buffer)); - readlink("/proc/self/exe", buffer, sizeof(buffer)); - exe_name = strrchr(buffer, '/'); - if (exe_name) - exe_name++; - else - exe_name = buffer; - if (strstr(exe_name, "spindlens")) { - exe_name2 = strrchr(exe_name, '-'); - if (exe_name2) - exe_name = exe_name2 + 1; - } return LA_FLG_BINDTO | LA_FLG_BINDFROM; } diff --git a/src/client/beboot/spindle_bootstrap.c b/src/client/beboot/spindle_bootstrap.c index 7805a9db..9c82c061 100644 --- a/src/client/beboot/spindle_bootstrap.c +++ b/src/client/beboot/spindle_bootstrap.c @@ -60,6 +60,7 @@ static char *client_lib; static char *opts_s; static char **daemon_args; static char *cachesize_s; +static char *executable_abspath; opt_t opts; @@ -231,7 +232,7 @@ static void get_executable() } debug_printf2("Sending request for executable %s\n", *cmdline); - exec_pathsearch(ldcsid, *cmdline, &executable, &errcode); + exec_pathsearch(ldcsid, *cmdline, &executable, &errcode, &executable_abspath); if (executable == NULL) { executable = *cmdline; @@ -256,7 +257,7 @@ static void adjust_script() if (!executable) return; - result = adjust_if_script(*cmdline, executable, cmdline, &new_executable, &new_cmdline); + result = adjust_if_script(*cmdline, executable, cmdline, &new_executable, &new_cmdline, executable_abspath); if (result != 0) return; diff --git a/src/client/client/Makefile.am b/src/client/client/Makefile.am index 4fc8b440..b6f03700 100644 --- a/src/client/client/Makefile.am +++ b/src/client/client/Makefile.am @@ -17,7 +17,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/../logging -I$(top_srcdir)/client_comlib -I$(top_s INTERCEPT_SRCS = intercept_open.c intercept_exec.c intercept_stat.c intercept_readlink.c intercept_spindleapi.c intercept.c spindle_regex.c patch_interception.c realpath.c $(top_srcdir)/../utils/fileutil.c -BASE_SRCS = client.c lookup.c should_intercept.c exec_util.c remap_exec.c lookup_libc.c $(top_srcdir)/../utils/parseloc.c $(top_srcdir)/../utils/getcpu.c +BASE_SRCS = client.c lookup.c should_intercept.c exec_util.c remap_exec.c lookup_libc.c $(top_srcdir)/../utils/parseloc.c $(top_srcdir)/../utils/getcpu.c adjust_argv.c libspindlec_socket_la_SOURCES = $(BASE_SRCS) libspindlec_socket_la_LIBADD = $(top_builddir)/client_comlib/libclient_socket.la $(top_builddir)/logging/libspindleclogc.la $(top_builddir)/shm_cache/libshmcache.la diff --git a/src/client/client/Makefile.in b/src/client/client/Makefile.in index 27afcbc1..d0241599 100644 --- a/src/client/client/Makefile.in +++ b/src/client/client/Makefile.in @@ -137,7 +137,7 @@ libspindlec_biter_la_DEPENDENCIES = \ am__objects_2 = client.lo lookup.lo should_intercept.lo exec_util.lo \ remap_exec.lo lookup_libc.lo \ $(top_builddir)/../utils/parseloc.lo \ - $(top_builddir)/../utils/getcpu.lo + $(top_builddir)/../utils/getcpu.lo adjust_argv.lo am_libspindlec_biter_la_OBJECTS = $(am__objects_2) libspindlec_biter_la_OBJECTS = $(am_libspindlec_biter_la_OBJECTS) @BITER_TRUE@am_libspindlec_biter_la_rpath = @@ -173,7 +173,8 @@ am__maybe_remake_depfiles = depfiles am__depfiles_remade = $(top_builddir)/../utils/$(DEPDIR)/getcpu.Plo \ $(top_builddir)/../utils/$(DEPDIR)/libspindle_audit_la-fileutil.Plo \ $(top_builddir)/../utils/$(DEPDIR)/parseloc.Plo \ - ./$(DEPDIR)/client.Plo ./$(DEPDIR)/exec_util.Plo \ + ./$(DEPDIR)/adjust_argv.Plo ./$(DEPDIR)/client.Plo \ + ./$(DEPDIR)/exec_util.Plo \ ./$(DEPDIR)/libspindle_audit_la-intercept.Plo \ ./$(DEPDIR)/libspindle_audit_la-intercept_exec.Plo \ ./$(DEPDIR)/libspindle_audit_la-intercept_open.Plo \ @@ -376,7 +377,7 @@ noinst_LTLIBRARIES = libspindle_audit.la $(am__append_1) \ AM_CFLAGS = -fvisibility=hidden AM_CPPFLAGS = -I$(top_srcdir)/../logging -I$(top_srcdir)/client_comlib -I$(top_srcdir)/../include -I$(top_srcdir)/shm_cache -I$(top_srcdir)/subaudit -I$(top_srcdir)/../utils -I$(top_srcdir)/auditclient INTERCEPT_SRCS = intercept_open.c intercept_exec.c intercept_stat.c intercept_readlink.c intercept_spindleapi.c intercept.c spindle_regex.c patch_interception.c realpath.c $(top_srcdir)/../utils/fileutil.c -BASE_SRCS = client.c lookup.c should_intercept.c exec_util.c remap_exec.c lookup_libc.c $(top_srcdir)/../utils/parseloc.c $(top_srcdir)/../utils/getcpu.c +BASE_SRCS = client.c lookup.c should_intercept.c exec_util.c remap_exec.c lookup_libc.c $(top_srcdir)/../utils/parseloc.c $(top_srcdir)/../utils/getcpu.c adjust_argv.c libspindlec_socket_la_SOURCES = $(BASE_SRCS) libspindlec_socket_la_LIBADD = $(top_builddir)/client_comlib/libclient_socket.la $(top_builddir)/logging/libspindleclogc.la $(top_builddir)/shm_cache/libshmcache.la libspindlec_pipe_la_SOURCES = $(BASE_SRCS) @@ -468,6 +469,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/../utils/$(DEPDIR)/getcpu.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/../utils/$(DEPDIR)/libspindle_audit_la-fileutil.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@$(top_builddir)/../utils/$(DEPDIR)/parseloc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adjust_argv.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exec_util.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libspindle_audit_la-intercept.Plo@am__quote@ # am--include-marker @@ -721,6 +723,7 @@ distclean: distclean-am -rm -f $(top_builddir)/../utils/$(DEPDIR)/getcpu.Plo -rm -f $(top_builddir)/../utils/$(DEPDIR)/libspindle_audit_la-fileutil.Plo -rm -f $(top_builddir)/../utils/$(DEPDIR)/parseloc.Plo + -rm -f ./$(DEPDIR)/adjust_argv.Plo -rm -f ./$(DEPDIR)/client.Plo -rm -f ./$(DEPDIR)/exec_util.Plo -rm -f ./$(DEPDIR)/libspindle_audit_la-intercept.Plo @@ -784,6 +787,7 @@ maintainer-clean: maintainer-clean-am -rm -f $(top_builddir)/../utils/$(DEPDIR)/getcpu.Plo -rm -f $(top_builddir)/../utils/$(DEPDIR)/libspindle_audit_la-fileutil.Plo -rm -f $(top_builddir)/../utils/$(DEPDIR)/parseloc.Plo + -rm -f ./$(DEPDIR)/adjust_argv.Plo -rm -f ./$(DEPDIR)/client.Plo -rm -f ./$(DEPDIR)/exec_util.Plo -rm -f ./$(DEPDIR)/libspindle_audit_la-intercept.Plo diff --git a/src/client/client/adjust_argv.c b/src/client/client/adjust_argv.c new file mode 100644 index 00000000..9bcd3205 --- /dev/null +++ b/src/client/client/adjust_argv.c @@ -0,0 +1,79 @@ +/* +This file is part of Spindle. For copyright information see the COPYRIGHT +file in the top level directory, or at +https://github.com/hpc/Spindle/blob/master/COPYRIGHT + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License (as published by the Free Software +Foundation) version 2.1 dated February 1999. This program is distributed in the +hope that it will be useful, but WITHOUT ANY WARRANTY; without even the IMPLIED +WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms +and conditions of the GNU Lesser General Public License for more details. You should +have received a copy of the GNU Lesser General Public License along with this +program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "config.h" +#include "client_api.h" +#include "client.h" + +extern int is_in_spindle_cache(const char *pathname); +extern int ldcsid; + +#if defined(HAVE_DL_ARGV) +extern char **_dl_argv; +static char **get_argv() +{ + return _dl_argv; +} +#else +static char **get_argv() +{ + return NULL; +} +#endif + +static void do_adjust(int arg_i, char **argv) +{ + int result; + char newpath[MAX_PATH_LEN+1], *s; + + if (!argv[arg_i]) + return; + + debug_printf2("Checking if argv[%d] (%s) needs to be fixed up\n", arg_i, argv[0]); + if (!is_in_spindle_cache(argv[arg_i])) { + return; + } + + newpath[0] = '\0'; + result = send_orig_path_request(ldcsid, argv[arg_i], newpath); + if (result == -1) { + debug_printf("Warning, not adjusting argv because server communication failed\n"); + return; + } + + if (strlen(argv[arg_i]) > strlen(newpath)) { + strcpy(argv[arg_i], newpath); + debug_printf2("Replaced argv[%d] with %s in place\n", arg_i, newpath); + } + else { + s = strdup(newpath); + argv[arg_i] = s; + debug_printf2("Replaced argv[%d] with %s from heap\n", arg_i, s); + } +} + +void adjust_argv_if_needed() +{ + char **argv; + + argv = get_argv(); + if (!argv) { + return; + } + + do_adjust(0, argv); + do_adjust(1, argv); +} diff --git a/src/client/client/client.c b/src/client/client/client.c index a50bb228..0b899e7e 100644 --- a/src/client/client/client.c +++ b/src/client/client/client.c @@ -78,6 +78,8 @@ char *orig_location; number_t number; static int have_stat_patches; +extern void adjust_argv_if_needed(); + static char *concatStrings(const char *str1, const char *str2) { static char buffer[MAX_PATH_LEN+1]; @@ -380,6 +382,7 @@ int client_init() { remap_executable(ldcsid); } + adjust_argv_if_needed(); if (opts & OPT_PATCHLDSO) { result = init_intercept_ldso_stat(); diff --git a/src/client/client/exec_util.c b/src/client/client/exec_util.c index 4a77709e..2ea4c75f 100644 --- a/src/client/client/exec_util.c +++ b/src/client/client/exec_util.c @@ -129,7 +129,7 @@ static int parse_interp_args(char *interp_line, char **interp_exec, char ***inte } -int adjust_if_script(const char *orig_path, char *reloc_path, char **argv, char **interp_path, char ***new_argv) +int adjust_if_script(const char *orig_path, char *reloc_path, char **argv, char **interp_path, char ***new_argv, char *found_from_pathsearch) { int result, fd, argc, interp_argc, i, j, errcode; char interpreter_line[MAX_PATH_LEN+1]; @@ -139,10 +139,10 @@ int adjust_if_script(const char *orig_path, char *reloc_path, char **argv, char if (argv && argv[0] && strcmp(argv[0], orig_path) != 0) { char *lastslash = strrchr(orig_path, '/'); - if (lastslash && strcmp(lastslash+1, argv[0]) != 0) { + if (!lastslash || (lastslash && strcmp(lastslash+1, argv[0]) != 0)) { debug_printf2("Not treating %s as a script because it's argv[0] (%s) is different than the executable, " "and Spindle can't emulate that\n", orig_path, argv[0]); - return SCRIPT_NOTSCRIPT; + return SCRIPT_CANTEMULATE; } } if (opts & OPT_REMAPEXEC) { @@ -177,7 +177,7 @@ int adjust_if_script(const char *orig_path, char *reloc_path, char **argv, char if (result == -1) { return SCRIPT_ENOENT; } - + debug_printf2("Exec operation requesting interpreter %s for script %s\n", interpreter, orig_path); get_relocated_file(ldcsid, interpreter, 1, &new_interpreter, &errcode, NULL); debug_printf2("Changed interpreter %s to %s for script %s\n", @@ -195,29 +195,34 @@ int adjust_if_script(const char *orig_path, char *reloc_path, char **argv, char *new_argv = (char **) spindle_malloc(sizeof(char*) * (argc + interp_argc + 2)); j = 0; - for (i = 0; i < interp_argc; i++) + for (i = 0; i < interp_argc; i++) { (*new_argv)[j++] = spindle_strdup(interpreter_args[i]); - /* If argv[0] is not a path, replace with absolute path to mimic kernel behavior */ - char *orig_path_copy = strdup( orig_path ); /* Preserve constness of orig_path. */ - (*new_argv)[j++] = (argv[0] && strchr(argv[0], '/')) ? argv[0] : orig_path_copy; + } + + if (found_from_pathsearch) { + (*new_argv)[j++] = spindle_strdup(found_from_pathsearch); + } + else { + char *orig_path_copy = spindle_strdup( orig_path ); /* Preserve constness of orig_path. */ + (*new_argv)[j++] = (argv[0] && strchr(argv[0], '/')) ? argv[0] : orig_path_copy; + } for (i = 1; i < argc; i++) { (*new_argv)[j++] = argv[i]; } (*new_argv)[j++] = NULL; *interp_path = new_interpreter; - debug_printf3("Rewritten interpreter cmdline is: "); - for (i = 0; i %s\n", newexec, *reloc_exec ? *reloc_exec : "NULL"); if (*reloc_exec) { + if (orig_file_abspath) { + *orig_file_abspath = spindle_strdup(newexec); + } found = 1; break; } diff --git a/src/client/client/exec_util.h b/src/client/client/exec_util.h index 6682eec9..177df0e1 100644 --- a/src/client/client/exec_util.h +++ b/src/client/client/exec_util.h @@ -20,9 +20,10 @@ #define SCRIPT_ERR -1 #define SCRIPT_ENOENT -2 #define SCRIPT_NOTSCRIPT -3 +#define SCRIPT_CANTEMULATE -4 -int adjust_if_script(const char *orig_path, char *reloc_path, char **argv, char **interp_path, char ***new_argv); -int exec_pathsearch(int ldcsid, const char *orig_exec, char **new_exec, int *errcode); +int adjust_if_script(const char *orig_path, char *reloc_path, char **argv, char **interp_path, char ***new_argv, char *found_from_pathsearch); +int exec_pathsearch(int ldcsid, const char *orig_exec, char **new_exec, int *errcode, char **orig_file_abspath); int isExecExcluded(const char *fname); int get_dirlists(char ***prefixes, char ***eexecs); diff --git a/src/client/client/intercept_exec.c b/src/client/client/intercept_exec.c index 2cfd6d8f..dbf9bae8 100644 --- a/src/client/client/intercept_exec.c +++ b/src/client/client/intercept_exec.c @@ -247,7 +247,7 @@ static void cleanEnvironment(char **envp, int num_modified) { static int prep_exec(const char *filepath, char **argv, char *newname, char *newpath, int newpath_size, - char ***new_argv, int errcode) + char ***new_argv, int errcode, char *found_from_pathsearch) { int result; char *interp_name; @@ -282,7 +282,7 @@ static int prep_exec(const char *filepath, char **argv, return 0; } - result = adjust_if_script(filepath, newname, argv, &interp_name, new_argv); + result = adjust_if_script(filepath, newname, argv, &interp_name, new_argv, found_from_pathsearch); if (opts & OPT_REMAPEXEC) { debug_printf2("exec'ing original path %s because we're running in remap mode\n", filepath); strncpy(newpath, filepath, newpath_size); @@ -307,6 +307,15 @@ static int prep_exec(const char *filepath, char **argv, spindle_free(newname); return -1; } + else if (result == SCRIPT_CANTEMULATE) { + debug_printf2("Running original script because we cannot emulate this script\n"); + strncpy(newpath, filepath, newpath_size); + newpath[newpath_size-1] = '\0'; + debug_printf("test_log(%s)\n", newname); + test_log(newname); + spindle_free(newname); + return 0; + } else if (result == 0) { // TODO: Mark filepath->newpath as future redirection for open strncpy(newpath, interp_name, newpath_size); @@ -374,12 +383,13 @@ static int find_exec(const char *filepath, char **argv, char *newpath, int newpa debug_printf("Exec file request returned %s -> %s with errcode %d\n", filepath, newname ? newname : "NULL", errcode); - return prep_exec(filepath, argv, newname, newpath, newpath_size, new_argv, errcode); + return prep_exec(filepath, argv, newname, newpath, newpath_size, new_argv, errcode, NULL); } static int find_exec_pathsearch(const char *filepath, char **argv, char *newpath, int newpath_size, char ***new_argv, char **envp, int *propogate_spindle) { char *newname = NULL; + char *orig_file_abspath = NULL; int result; int errcode; int reloc_exec; @@ -410,7 +420,7 @@ static int find_exec_pathsearch(const char *filepath, char **argv, char *newpath } sync_cwd(); - result = exec_pathsearch(ldcsid, filepath, &newname, &errcode); + result = exec_pathsearch(ldcsid, filepath, &newname, &errcode, &orig_file_abspath); if (result == -1) { set_errno(errcode); return -1; @@ -418,13 +428,14 @@ static int find_exec_pathsearch(const char *filepath, char **argv, char *newpath debug_printf("Exec file request returned %s -> %s with errcode %d\n", filepath, newname ? newname : "NULL", errcode); - return prep_exec(filepath, argv, newname, newpath, newpath_size, new_argv, errcode); + return prep_exec(filepath, argv, newname, newpath, newpath_size, new_argv, errcode, orig_file_abspath); } int execl_wrapper(const char *path, const char *arg0, ...) { int error, result, propogate_spindle; char newpath[MAX_PATH_LEN+1]; + newpath[0] = '\0'; VARARG_TO_ARGV; @@ -458,6 +469,7 @@ int execv_wrapper(const char *path, char *const argv[]) char newpath[MAX_PATH_LEN+1]; char **new_argv = NULL; int result, propogate_spindle; + newpath[0] = '\0'; debug_printf2("Intercepted execv on %s\n", path); result = find_exec(path, (char **) argv, newpath, MAX_PATH_LEN+1, &new_argv, NULL, &propogate_spindle); @@ -482,6 +494,7 @@ int execle_wrapper(const char *path, const char *arg0, ...) char **new_envp = NULL; char newpath[MAX_PATH_LEN+1]; int propogate_spindle, env_modified = 0; + newpath[0] = '\0'; VARARG_TO_ARGV; @@ -515,6 +528,7 @@ int execve_wrapper(const char *path, char *const argv[], char *const envp[]) char **new_envp = NULL; int propogate_spindle, env_modified; int result; + newpath[0] = '\0'; debug_printf2("Intercepted execve on %s\n", path); result = find_exec(path, (char **) argv, newpath, MAX_PATH_LEN+1, &new_argv, (char **) envp, &propogate_spindle); @@ -536,7 +550,8 @@ int execlp_wrapper(const char *path, const char *arg0, ...) int error, result; char newpath[MAX_PATH_LEN+1]; int propogate_spindle; - + newpath[0] = '\0'; + VARARG_TO_ARGV; debug_printf2("Intercepted execlp on %s\n", path); result = find_exec_pathsearch(path, argv, newpath, MAX_PATH_LEN+1, &new_argv, NULL, &propogate_spindle); @@ -565,16 +580,17 @@ int execvp_wrapper(const char *path, char *const argv[]) char **new_argv = NULL; int result; int propogate_spindle; + newpath[0] = '\0'; debug_printf2("Intercepted execvp of %s\n", path); result = find_exec_pathsearch(path, (char **) argv, newpath, MAX_PATH_LEN+1, &new_argv, NULL, &propogate_spindle); if (result == -1) { - debug_printf("execvp redirection of %s returning error code\n", path); + debug_printf("execvp redirection of %s returning error code\n", path); return result; } debug_printf("execvp redirection of %s to %s\n", path, newpath); - updateEnvironment(NULL, NULL, propogate_spindle); + updateEnvironment(NULL, NULL, propogate_spindle); result = orig_execvp(newpath, new_argv ? new_argv : argv); if (new_argv) spindle_free(new_argv); @@ -588,7 +604,8 @@ int execvpe_wrapper(const char *path, char *const argv[], char *const envp[]) char **new_envp = NULL; int propogate_spindle, env_modified; int result; - + newpath[0] = '\0'; + debug_printf2("Intercepted execvpe on %s\n", path); result = find_exec_pathsearch(path, (char **) argv, newpath, MAX_PATH_LEN+1, &new_argv, (char **) envp, &propogate_spindle); if (result == -1) { diff --git a/src/client/client/intercept_readlink.c b/src/client/client/intercept_readlink.c index 0a326330..af4266a1 100644 --- a/src/client/client/intercept_readlink.c +++ b/src/client/client/intercept_readlink.c @@ -57,11 +57,10 @@ ssize_t readlink_wrapper(const char *path, char *buf, size_t bufsiz) { char resultpath[MAX_PATH_LEN+1]; int intercept_result, result, readlink_errcode; - size_t len; + ssize_t len; ssize_t rl_result; check_for_fork(); - memset(resultpath, 0, sizeof(resultpath)); intercept_result = stat_filter(path); if (intercept_result == ORIG_CALL) { diff --git a/src/client/client/intercept_stat.c b/src/client/client/intercept_stat.c index b459cdd2..069b6fb1 100644 --- a/src/client/client/intercept_stat.c +++ b/src/client/client/intercept_stat.c @@ -264,6 +264,9 @@ int ldso_xstat(int ver, const char *filename, struct stat *buf) (void)ver; int result; result = handle_stat(filename, buf, FROM_LDSO); + if (result == ORIG_STAT) { + result = stat(filename, buf); + } if (result != 0) { if (*ldso_errno) *ldso_errno = -result; @@ -276,7 +279,10 @@ int ldso_lxstat(int ver, const char *filename, struct stat *buf) { (void)ver; int result; - result = handle_stat(filename, buf, FROM_LDSO | IS_LSTAT); + result = handle_stat(filename, buf, FROM_LDSO | IS_LSTAT); + if (result == ORIG_STAT) { + result = lstat(filename, buf); + } if (result != 0) { if (*ldso_errno) *ldso_errno = -result; diff --git a/src/client/config.h.in b/src/client/config.h.in index 6c5eae90..6d531908 100644 --- a/src/client/config.h.in +++ b/src/client/config.h.in @@ -36,6 +36,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H +/* ld.so exports the _dl_argv variable */ +#undef HAVE_DL_ARGV + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H diff --git a/src/client/configure b/src/client/configure index 236528aa..43fcc696 100755 --- a/src/client/configure +++ b/src/client/configure @@ -13215,6 +13215,33 @@ _ACEOF fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking wheter ld.so has the _dl_argv variable" >&5 +$as_echo_n "checking wheter ld.so has the _dl_argv variable... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char **_dl_argv; +int +main () +{ +(void) _dl_argv; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + HAVE_DL_ARGV="true";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "x$HAVE_DL_ARGV" == "xtrue"; then + +$as_echo "#define HAVE_DL_ARGV 1" >>confdefs.h + +fi #Usage logging diff --git a/src/fe/config.h.in b/src/fe/config.h.in index 357feea0..5d9963cc 100644 --- a/src/fe/config.h.in +++ b/src/fe/config.h.in @@ -60,6 +60,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H +/* ld.so exports the _dl_argv variable */ +#undef HAVE_DL_ARGV + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H diff --git a/src/fe/configure b/src/fe/configure index 75088c9a..53335db1 100755 --- a/src/fe/configure +++ b/src/fe/configure @@ -17065,6 +17065,33 @@ _ACEOF fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking wheter ld.so has the _dl_argv variable" >&5 +$as_echo_n "checking wheter ld.so has the _dl_argv variable... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char **_dl_argv; +int +main () +{ +(void) _dl_argv; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + HAVE_DL_ARGV="true";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "x$HAVE_DL_ARGV" == "xtrue"; then + +$as_echo "#define HAVE_DL_ARGV 1" >>confdefs.h + +fi #Usage logging diff --git a/src/server/config.h.in b/src/server/config.h.in index 6eea236a..931b768c 100644 --- a/src/server/config.h.in +++ b/src/server/config.h.in @@ -42,6 +42,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H +/* ld.so exports the _dl_argv variable */ +#undef HAVE_DL_ARGV + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H diff --git a/src/server/configure b/src/server/configure index a747c739..cb6d1366 100755 --- a/src/server/configure +++ b/src/server/configure @@ -17062,6 +17062,33 @@ _ACEOF fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking wheter ld.so has the _dl_argv variable" >&5 +$as_echo_n "checking wheter ld.so has the _dl_argv variable... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +extern char **_dl_argv; +int +main () +{ +(void) _dl_argv; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + HAVE_DL_ARGV="true";{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "x$HAVE_DL_ARGV" == "xtrue"; then + +$as_echo "#define HAVE_DL_ARGV 1" >>confdefs.h + +fi #Usage logging diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 0ba9638f..fa0ea36a 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -1,7 +1,7 @@ noinst_PROGRAMS = libgenerator ABS_TEST_DIR = $(abspath $(top_builddir)/testsuite) -BUILT_SOURCES = libtest10.so libtest11.so libtest12.so libtest13.so libtest14.so libtest15.so libtest16.so libtest17.so libtest18.so libtest19.so libtest20.so libtest50.so libtest100.so libtest500.so libtest1000.so libtest2000.so libtest4000.so libtest6000.so libtest8000.so libtest10000.so libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libsymlink.so libdepC.so libdepB.so libdepA.so libcxxexceptB.so libcxxexceptA.so origin_dir/liboriginlib.so origin_dir/origin_subdir/liborigintarget.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc preload_file_list test_driver test_driver_libs retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py spindle_exec_test spindle_deactivated.sh liblocal.so symbind_test interpreter_test interpreter_test_dir/interpreter_test_perl alias/aliastest.py +BUILT_SOURCES = libtest10.so libtest11.so libtest12.so libtest13.so libtest14.so libtest15.so libtest16.so libtest17.so libtest18.so libtest19.so libtest20.so libtest50.so libtest100.so libtest500.so libtest1000.so libtest2000.so libtest4000.so libtest6000.so libtest8000.so libtest10000.so libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libsymlink.so libdepC.so libdepB.so libdepA.so libcxxexceptB.so libcxxexceptA.so origin_dir/liboriginlib.so origin_dir/origin_subdir/liborigintarget.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc preload_file_list test_driver test_driver_libs retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py spindle_exec_test spindle_deactivated.sh liblocal.so symbind_test interpreter_test interpreter_test_dir/interpreter_test_perl alias/aliastest.py exec_shell.sh exec_shell.tcsh exec_shell_expected_output exec_shell exec_shell_env.sh if BGQ_BLD DYNAMIC_FLAG=-dynamic @@ -420,4 +420,19 @@ interpreter_test_dir/interpreter_test_perl: interpreter_test_perl_template inter interpreter_test: interpreter_test_template $(AM_V_GEN)cp $< $@; chmod 700 $@ -CLEANFILES = libtest10.c libtest11.c libtest12.c libtest13.c libtest14.c libtest15.c libtest16.c libtest17.c libtest18.c libtest19.c libtest20.c libtest10.so libtest50.c libtest50.so libtest100.c libtest100.so libtest500.c libtest500.so libtest1000.c libtest1000.so libtest2000.c libtest2000.so libtest4000.c libtest4000.so libtest6000.c libtest6000.so libtest8000.c libtest8000.so libtest10000.c libtest10000.so libsymlink.so libdepA.so libdepB.so libdepC.so libcxxexceptA.so libcxxexceptB.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc test_driver test_driver_libs preload_file_list retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libtls1.so libtls2.so libtls3.so libtls4.so libtls5.so libtls6.so libtls7.so libtls8.so libtls9.so libtls10.so libtls11.so libtls12.so libtls13.so libtls14.so libtls15.so libtls16.so libtls17.so libtls18.so libtls19.so libtls20.so symbind_test libsymbind_a.so libsymbind_b.so libsymbind_c.so libsymbind_d.so libsymbind_e.so libsymbind_f.so libsymbind_g.so interpreter_test interpreter_test_dir/interpreter_test_perl alias +exec_shell.sh: $(srcdir)/exec_shell_template.sh + $(AM_V_GEN)cp $< $@; chmod 700 $@ + +exec_shell.tcsh: $(srcdir)/exec_shell_template.tcsh + $(AM_V_GEN)cp $< $@; chmod 700 $@ + +exec_shell_env.sh: $(srcdir)/exec_shell_env_template.sh + $(AM_V_GEN)cp $< $@; chmod 700 $@ + +exec_shell_expected_output: $(srcdir)/exec_shell_expected_output_template + $(AM_V_GEN)cp $< $@ + +exec_shell: $(srcdir)/exec_shell.c + $(AM_V_CCLD)$(CC) $(CFLAGS) -o $@ $< + +CLEANFILES = libtest10.c libtest11.c libtest12.c libtest13.c libtest14.c libtest15.c libtest16.c libtest17.c libtest18.c libtest19.c libtest20.c libtest10.so libtest50.c libtest50.so libtest100.c libtest100.so libtest500.c libtest500.so libtest1000.c libtest1000.so libtest2000.c libtest2000.so libtest4000.c libtest4000.so libtest6000.c libtest6000.so libtest8000.c libtest8000.so libtest10000.c libtest10000.so libsymlink.so libdepA.so libdepB.so libdepC.so libcxxexceptA.so libcxxexceptB.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc test_driver test_driver_libs preload_file_list retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libtls1.so libtls2.so libtls3.so libtls4.so libtls5.so libtls6.so libtls7.so libtls8.so libtls9.so libtls10.so libtls11.so libtls12.so libtls13.so libtls14.so libtls15.so libtls16.so libtls17.so libtls18.so libtls19.so libtls20.so symbind_test libsymbind_a.so libsymbind_b.so libsymbind_c.so libsymbind_d.so libsymbind_e.so libsymbind_f.so libsymbind_g.so interpreter_test interpreter_test_dir/interpreter_test_perl alias exec_shell.sh exec_shell.tcsh exec_shell_env.sh exec_shell_expected_output exec_shell diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 28530f73..290fe9a1 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -357,7 +357,8 @@ BUILT_SOURCES = libtest10.so libtest11.so libtest12.so libtest13.so \ hello_rx.py hello_.py hello_l.py badlink.py spindle_exec_test \ spindle_deactivated.sh liblocal.so symbind_test \ interpreter_test interpreter_test_dir/interpreter_test_perl \ - alias/aliastest.py + alias/aliastest.py exec_shell.sh exec_shell.tcsh \ + exec_shell_expected_output exec_shell exec_shell_env.sh @BGQ_BLD_FALSE@DYNAMIC_FLAG = @BGQ_BLD_TRUE@DYNAMIC_FLAG = -dynamic @BGQ_BLD_FALSE@IS_BLUEGENE = false @@ -397,7 +398,9 @@ CLEANFILES = libtest10.c libtest11.c libtest12.c libtest13.c \ libsymbind_a.so libsymbind_b.so libsymbind_c.so \ libsymbind_d.so libsymbind_e.so libsymbind_f.so \ libsymbind_g.so interpreter_test \ - interpreter_test_dir/interpreter_test_perl alias + interpreter_test_dir/interpreter_test_perl alias exec_shell.sh \ + exec_shell.tcsh exec_shell_env.sh exec_shell_expected_output \ + exec_shell all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am @@ -1097,6 +1100,21 @@ interpreter_test_dir/interpreter_test_perl: interpreter_test_perl_template inter interpreter_test: interpreter_test_template $(AM_V_GEN)cp $< $@; chmod 700 $@ +exec_shell.sh: $(srcdir)/exec_shell_template.sh + $(AM_V_GEN)cp $< $@; chmod 700 $@ + +exec_shell.tcsh: $(srcdir)/exec_shell_template.tcsh + $(AM_V_GEN)cp $< $@; chmod 700 $@ + +exec_shell_env.sh: $(srcdir)/exec_shell_env_template.sh + $(AM_V_GEN)cp $< $@; chmod 700 $@ + +exec_shell_expected_output: $(srcdir)/exec_shell_expected_output_template + $(AM_V_GEN)cp $< $@ + +exec_shell: $(srcdir)/exec_shell.c + $(AM_V_CCLD)$(CC) $(CFLAGS) -o $@ $< + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/testsuite/exec_shell.c b/testsuite/exec_shell.c new file mode 100644 index 00000000..60429bea --- /dev/null +++ b/testsuite/exec_shell.c @@ -0,0 +1,469 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + run_pathsearch = 0, + run_dot, + run_relative, + run_abs, + run_done +} run_t; + +typedef enum { + shell_none_sh = 0, + shell_none_tcsh, + shell_sh, + shell_bash, + shell_tcsh, + shell_env, + shell_done +} shell_t; + +typedef enum { + arg_match = 0, + arg_partial, + arg_abs, + arg_junk, + arg_done +} arg_t; + +typedef enum { + exect_v, + exect_vp, + exect_done +} exec_type_t; + +static char cwd[4097]; +static int print_results = 0; + +static int have_sh; +static int have_bash; +static int have_tcsh; +static int have_env; + +/** + * Initialization and setup + **/ +static int init() +{ + char *newpath; + char *curpath; + char *sresult; + size_t len; + int result; + struct stat buf; + + memset(cwd, 0, sizeof(cwd)); + sresult = getcwd(cwd, sizeof(cwd)-1); + if (!sresult) { + perror("Could not getcwd"); + return -1; + } + + sresult = realpath(cwd, NULL); + if (!sresult) { + perror("Could not realpath"); + return -1; + } + strncpy(cwd, sresult, sizeof(cwd)-1); + free(sresult); + sresult = NULL; + + result = chdir(cwd); + if (result == -1) { + perror("Could not chdir"); + return -1; + } + + curpath = getenv("PATH"); + len = curpath ? strlen(curpath) : 0; + len += strlen(cwd); + len += 2; + + newpath = (char *) malloc(len); + snprintf(newpath, len, "%s%s%s", cwd, curpath ? ":" : "", curpath ? curpath : ""); + setenv("PATH", newpath, 1); + + result = stat("/bin/sh", &buf); + have_sh = (result == 0); + result = stat("/bin/bash", &buf); + have_bash = (result == 0); + result = stat("/bin/tcsh", &buf); + have_tcsh = (result == 0); + result = stat("/bin/env", &buf); + have_env = (result == 0); + + return 0; +} + +/** + * Run the appropriate script/test based on the inputs and return the scripts first output line if successful. + **/ +static char* run(run_t rt, shell_t st, arg_t at, exec_type_t et, int *skip) +{ + const char* argv[8]; + const char *launcher = NULL, *exe, *ext; + char abspath[4200]; + char script_name[4200]; + char *s, *line; + int i = 0, result, status; + int fds[2]; + FILE *f; + pid_t pid; + + memset(abspath, 0, sizeof(abspath)); + snprintf(abspath, sizeof(abspath)-1, "%s/exec_shellXXXXXXXXX", cwd); + memset(script_name, 0, sizeof(script_name)); + + if (et == exect_v && rt == run_pathsearch) { + *skip = 1; + return NULL; + } + + *skip = 0; + switch (st) { + case shell_none_sh: + if (!have_sh) { + *skip = 1; + return NULL; + } + ext = ".sh"; + break; + case shell_none_tcsh: + if (!have_tcsh) { + *skip = 1; + return NULL; + } + ext = ".tcsh"; + break; + case shell_sh: + if (!have_sh) { + *skip = 1; + return NULL; + } + ext = ".sh"; + launcher = "/bin/sh"; + break; + case shell_bash: + if (!have_bash) { + *skip = 1; + return NULL; + } + ext = ".sh"; + launcher = "/bin/bash"; + break; + case shell_tcsh: + if (!have_tcsh) { + *skip = 1; + return NULL; + } + ext = ".tcsh"; + launcher = "/bin/tcsh"; + break; + case shell_env: + if (!have_env || !have_sh) { + *skip = 1; + return NULL; + } + ext = "_env.sh"; + break; + case shell_done: + launcher = NULL; + return NULL; + } + + memset(script_name, 0, sizeof(script_name)); + switch (rt) { + case run_pathsearch: + strncpy(script_name, "exec_shellXXXXXXXXX", sizeof(script_name)-1); + break; + case run_dot: + strncpy(script_name, "./exec_shellXXXXXXXXX", sizeof(script_name)-1); + break; + case run_relative: + strncpy(script_name, "../testsuite/exec_shellXXXXXXXXX", sizeof(script_name)-1); + break; + case run_abs: + strncpy(script_name, abspath, sizeof(script_name)); + break; + case run_done: + return NULL; + } + s = strstr(script_name, "XXXXXXXXX"); + memcpy(s, ext, strlen(ext)+1); + s = strstr(abspath, "XXXXXXXXX"); + if (s) + memcpy(s, ext, strlen(ext)+1); + + exe = launcher ? launcher : script_name; + if (launcher) + argv[i++] = launcher; + argv[i++] = script_name; + + //Muck with argv[0] and make it different than expected. + switch (at) { + case arg_match: + break; + case arg_partial: + argv[0] = "exe_target.sh"; + break; + case arg_abs: + argv[0] = abspath; + break; + case arg_junk: + argv[0] = "junk"; + break; + case arg_done: + return NULL; + } + + argv[i++] = "--arg1"; + argv[i++] = "--arg2"; + + argv[i++] = NULL; + + result = pipe(fds); + if (result == -1) { + perror("Could not pipe"); + return NULL; + } + + pid = fork(); + if (pid == -1) { + perror("Could not fork"); + close(fds[0]); + close(fds[1]); + return NULL; + } + else if (pid == 0) { + dup2(fds[1], 1); + close(fds[0]); + if (et == exect_v) { + execv(exe, (char* const*) argv); + } + else if (et == exect_vp) { + execvp(exe, (char* const*) argv); + } + perror("Failed to exe"); + return NULL; + } + + close(fds[1]); + line = (char *) malloc(4096); + f = fdopen(fds[0], "r"); + s = fgets(line, 4096, f); + if (s != line) { + free(line); + fprintf(stderr, "Could not read input from script\n"); + line = NULL; + } + fclose(f); + + do { + result = waitpid(pid, &status, 0); + } while (result == -1 && errno == EINTR); + if (result == -1) { + perror("waitpid error"); + return NULL; + } + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + fprintf(stderr, "Child process returned unexpected value %d from waitpid (exited = %d, exitstatus = %d ; signaled = %d, termsig = %d)\n", + status, (int) WIFEXITED(status), (int) WEXITSTATUS(status), (int) WIFSIGNALED(status), (int) WTERMSIG(status)); + fprintf(stderr, "exec = %s; arg[0] = %s; argv[1] = %s; argv[2] = %s; argv[3] = %s\n", + exe, argv[0] ? argv[0] : "[NULL]", argv[1] ? argv[1] : "[NULL]", argv[2] ? argv[2] : "[NULL]", argv[3] ? argv[3] : "[NULL]"); + return NULL; + } + + return line; +} + +/** + * Read one line from the file containing the expected output + **/ +static FILE* result_file = NULL; +static char *read_result() +{ + char *s, *t; + if (!result_file) { + result_file = fopen("./exec_shell_expected_output", "r"); + if (!result_file) { + perror("Could not open result file ./exec_shell_expected_output"); + exit(-1); + } + } + s = (char *) malloc(4096); + t = fgets(s, 4096, result_file); + if (s != t) { + fprintf(stderr, "Could not read from ./exec_shell_expected_output"); + return NULL; + } + return s; +} + +/** + * Debugging assist method to print out what combo of paramters we were running + **/ +#define STR(X) STR2(X) +#define STR2(X) #X +#define STRCASE(X) case X: s = STR(X); break +char *test_string(run_t rt, shell_t st, arg_t at, exec_type_t et) +{ + const char *rs, *ss, *as, *es, *s = NULL; + char buffer[4096]; + + switch (rt) { + STRCASE(run_pathsearch); + STRCASE(run_dot); + STRCASE(run_relative); + STRCASE(run_abs); + STRCASE(run_done); + } + rs = s; + switch (st) { + STRCASE(shell_none_sh); + STRCASE(shell_none_tcsh); + STRCASE(shell_sh); + STRCASE(shell_bash); + STRCASE(shell_tcsh); + STRCASE(shell_env); + STRCASE(shell_done); + } + ss = s; + switch (at) { + STRCASE(arg_match); + STRCASE(arg_partial); + STRCASE(arg_abs); + STRCASE(arg_junk); + STRCASE(arg_done); + } + as = s; + switch (et) { + STRCASE(exect_v); + STRCASE(exect_vp); + STRCASE(exect_done); + } + es = s; + + snprintf(buffer, sizeof(buffer), "run_t = '%s', shell_t = '%s', arg_t = '%s', exect = '%s'", rs, ss, as, es); + return strdup(buffer); +} + +/** + * Easier debug printing by removing newlines + **/ +static void strip_newline(char *s) { + if (!s) + return; + for (; *s != '\0'; s++) + if (*s == '\n') { + *s = '\0'; + break; + } +} + +/** + * Run a test by exec'ing a script that prints its argv[]. We'll invoke that script a bunch of different ways, + * based on parameters, and read a line from the expected results output file. If the two lines match, that + * subtest passes. + */ +static int run_test(run_t rt, shell_t st, arg_t at, exec_type_t et) { + char *test_line = NULL, *result_line = NULL, *errstr = NULL; + int skip = 0; + int result = -1; + + test_line = run(rt, st, at, et, &skip); + if (print_results) { + if (skip) { + printf("Skipped\n"); + return 0; + } + assert(test_line); + printf("%s", test_line); + free(test_line); + return 0; + } + result_line = read_result(); + strip_newline(test_line); + strip_newline(result_line); + + if (skip) { + result = 0; + goto done; + } + + if (!test_line) { + result = -1; + goto done; + } + if (!result_line) { + fprintf(stderr, "Internal test error. No results to compare to\n"); + result = -1; + goto done; + } + + if (strcmp(test_line, result_line) != 0) { + fprintf(stderr, "Error: Test line '%s' and result line '%s' do not match\n", test_line, result_line); + result = -1; + goto done; + } + + result = 0; + + done: + if (result != 0) { + errstr = test_string(rt, st, at, et); + fprintf(stderr, "Test failure while running: %s\n", errstr); + } + if (test_line) + free(test_line); + if (result_line) + free(result_line); + if (errstr) + free(errstr); + return result; +} + +int main(int argc, char *argv[]) +{ + int r, s, a, e; + int result; + int had_error = 0; + + if (argc >= 2 && strcmp(argv[1], "--print") == 0) { + print_results = 1; + } + result = init(); + if (result == -1) + return -1; + + for (r = 0; r < (int) run_done; r++) { + for (s = 0; s < (int) shell_done; s++) { + for (a = 0; a < (int) arg_done; a++) { + for (e = 0; e < (int) exect_done; e++) { + result = run_test((run_t) r, (shell_t) s, (arg_t) a, (exec_type_t) e); + if (result == -1) { + had_error = 1; + } + } + } + } + } + if (result_file) + fclose(result_file); + if (had_error) { + fprintf(stderr, "Failure\n"); + return -1; + } + printf("PASSED.\n"); + return 0; +} \ No newline at end of file diff --git a/testsuite/exec_shell_env_template.sh b/testsuite/exec_shell_env_template.sh new file mode 100644 index 00000000..4e5b9ce4 --- /dev/null +++ b/testsuite/exec_shell_env_template.sh @@ -0,0 +1,6 @@ +#!/bin/env sh + +REALCWD=`realpath $PWD` +echo $0 $* | sed "s#$REALCWD#ABS#g" + +exit 0 diff --git a/testsuite/exec_shell_expected_output_template b/testsuite/exec_shell_expected_output_template new file mode 100644 index 00000000..77f27f40 --- /dev/null +++ b/testsuite/exec_shell_expected_output_template @@ -0,0 +1,192 @@ +Skipped +ABS/exec_shell.sh --arg1 --arg2 +Skipped +ABS/exec_shell.sh --arg1 --arg2 +Skipped +ABS/exec_shell.sh --arg1 --arg2 +Skipped +ABS/exec_shell.sh --arg1 --arg2 +Skipped +ABS/exec_shell.tcsh --arg1 --arg2 +Skipped +ABS/exec_shell.tcsh --arg1 --arg2 +Skipped +ABS/exec_shell.tcsh --arg1 --arg2 +Skipped +ABS/exec_shell.tcsh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.sh --arg1 --arg2 +Skipped +exec_shell.tcsh --arg1 --arg2 +Skipped +exec_shell.tcsh --arg1 --arg2 +Skipped +exec_shell.tcsh --arg1 --arg2 +Skipped +exec_shell.tcsh --arg1 --arg2 +Skipped +ABS/exec_shell_env.sh --arg1 --arg2 +Skipped +ABS/exec_shell_env.sh --arg1 --arg2 +Skipped +ABS/exec_shell_env.sh --arg1 --arg2 +Skipped +ABS/exec_shell_env.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.sh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell.tcsh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +./exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.sh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell.tcsh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +../testsuite/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.sh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell.tcsh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 +ABS/exec_shell_env.sh --arg1 --arg2 diff --git a/testsuite/exec_shell_template.sh b/testsuite/exec_shell_template.sh new file mode 100755 index 00000000..831d5aac --- /dev/null +++ b/testsuite/exec_shell_template.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +REALCWD=`realpath $PWD` +echo $0 $* | sed "s#$REALCWD#ABS#g" + +exit 0 diff --git a/testsuite/exec_shell_template.tcsh b/testsuite/exec_shell_template.tcsh new file mode 100755 index 00000000..fbd27798 --- /dev/null +++ b/testsuite/exec_shell_template.tcsh @@ -0,0 +1,6 @@ +#!/bin/tcsh + +setenv REALCWD `realpath $PWD` +echo $0 $* | sed "s#${REALCWD}#ABS#g" + +exit 0 \ No newline at end of file diff --git a/testsuite/runTests_template b/testsuite/runTests_template index d14acb64..2e04b924 100644 --- a/testsuite/runTests_template +++ b/testsuite/runTests_template @@ -190,6 +190,9 @@ CHECK_RETCODE ./run_driver --serial ./interpreter_test CHECK_RETCODE +./run_driver --serial ./exec_shell +CHECK_RETCODE + if [[ $GLOBAL_RESULT != 0 ]]; then echo SOME TESTS FAILED exit -1