martin 98/12/22 16:20:59
Modified: src/ap ap_execve.c
Log:
The hashbang emulation code was "forgetting" to use the default shell
for scripts without a "#!/interpreter" staring line. Now it behaves
like a regular shell or a regular OS's execve() implementation.
Revision Changes Path
1.10 +59 -17 apache-1.3/src/ap/ap_execve.c
Index: ap_execve.c
===================================================================
RCS file: /export/home/cvs/apache-1.3/src/ap/ap_execve.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- ap_execve.c 1998/03/31 12:52:10 1.9
+++ ap_execve.c 1998/12/23 00:20:58 1.10
@@ -126,7 +126,8 @@
}
va_end(adummy);
- argv = (char **) malloc((argc + 2) * sizeof(*argv));
+ if ((argv = (char **) malloc((argc + 2) * sizeof(*argv))) == NULL)
+ return -1;
/* Pass two --- copy the argument strings into the result space */
va_start(adummy, argv0);
@@ -143,10 +144,27 @@
return ret;
}
+/* Count number of entries in vector "args", including the trailing NULL
entry
+ */
+static int
+count_args(const char **args)
+{
+ int i;
+ for (i = 0; args[i] != NULL; ++i) {
+ continue;
+ }
+ return i+1;
+}
+
+/* Emulate the execve call, respecting a #!/interpreter line if present.
+ * On "real" unixes, the kernel does this.
+ * We have to fiddle with the argv array to make it work on platforms
+ * which don't support the "hashbang" interpreter line by default.
+ */
int ap_execve(const char *filename, const char *argv[],
const char *envp[])
{
- const char *argv0 = argv[0];
+ const char **script_argv;
extern char **environ;
if (envp == NULL) {
@@ -174,26 +192,50 @@
* ELOOP filename contains a circular reference (i.e., via a symbolic
link)
*/
- if (errno == ENOEXEC
- /* Probably a script.
- * Have a look; if there's a "#!" header then try to emulate
- * the feature found in all modern OS's:
- * Interpret the line following the #! as a command line
- * in shell style.
- */
- && (argv = hashbang(filename, argv)) != NULL) {
+ if (errno == ENOEXEC) {
+ /* Probably a script.
+ * Have a look; if there's a "#!" header then try to emulate
+ * the feature found in all modern OS's:
+ * Interpret the line following the #! as a command line
+ * in shell style.
+ */
+ if ((script_argv = hashbang(filename, argv)) != NULL) {
+
+ /* new filename is the interpreter to call */
+ filename = script_argv[0];
+
+ /* Restore argv[0] as on entry */
+ if (argv[0] != NULL) {
+ script_argv[0] = argv[0];
+ }
- /* new filename is the interpreter to call */
- filename = argv[0];
+ execve(filename, script_argv, envp);
- /* Restore argv[0] as on entry */
- if (argv0 != NULL) {
- argv[0] = argv0;
+ free(script_argv);
}
+ /*
+ * Script doesn't start with a hashbang line!
+ * So, try to have the default shell execute it.
+ * For this, the size of argv must be increased by one
+ * entry: the shell's name. The remaining args are appended.
+ */
+ else {
+ int i = count_args(argv) + 1; /* +1 for leading SHELL_PATH */
+
+ if ((script_argv = malloc(sizeof(*script_argv) * i)) == NULL)
+ return -1;
+
+ script_argv[0] = SHELL_PATH;
+
+ while (i > 0) {
+ script_argv[i] = argv[i-1];
+ --i;
+ }
- execve(filename, argv, envp);
+ execve(SHELL_PATH, script_argv, envp);
- free(argv);
+ free(script_argv);
+ }
}
return -1;
}