From 540e1132b996055e07ae0040b2dca8d87a1792bf Mon Sep 17 00:00:00 2001
From: HOLZSCHUCH Nicolas <nicolas.holzschuch@inria.fr>
Date: Tue, 2 Nov 2021 17:15:24 +0100
Subject: [PATCH] Bug fixing with fork and environment variables

---
 awk-23.30.1/src/main.c         |   1 +
 bsd_find/function.c            |  11 ++--
 ios_system.m                   | 113 +++++++++++++++++++++++++++++++--
 shell_cmds/env/env.c           |   1 +
 shell_cmds/printenv/printenv.c |   1 +
 5 files changed, 116 insertions(+), 11 deletions(-)

diff --git a/awk-23.30.1/src/main.c b/awk-23.30.1/src/main.c
index 7236fc69..5e491ff8 100644
--- a/awk-23.30.1/src/main.c
+++ b/awk-23.30.1/src/main.c
@@ -39,6 +39,7 @@ const char	*version = "version 20070501";
 // #else
 #define COMPAT_MODE(func, mode) 1
 // #endif
+#include <TargetConditionals.h>
 #include "ios_error.h"
 
 extern	char	**environ;
diff --git a/bsd_find/function.c b/bsd_find/function.c
index d4747238..d4cd725b 100644
--- a/bsd_find/function.c
+++ b/bsd_find/function.c
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
 #include <ctype.h>
 
 #include "find.h"
+#include <TargetConditionals.h>
 #include "ios_error.h"
 
 
@@ -614,6 +615,10 @@ c_empty(OPTION *option, char ***argvp __unused)
  *	The primary -ok differs from -exec in that it requests affirmation
  *	of the user before executing the utility.
  */
+// iOS addition: to reset the directory before execution of each command.
+// Not sure this is necessary anymore.
+extern int ios_fchdir_nolock(const int fd);
+
 int
 f_exec(PLAN *plan, FTSENT *entry)
 {
@@ -660,8 +665,6 @@ doexec:	if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
 	fflush(stdout);
 	fflush(stderr);
 
-    char* pushDirectory = NULL;
-    pushDirectory = getcwd(pushDirectory, MAXPATHLEN);
 	switch (pid = fork()) {
 	case -1:
 		err(1, "fork");
@@ -670,7 +673,7 @@ doexec:	if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
 	// case 0: {
 		/* change dir back from where we started */
 		if (!(plan->flags & F_EXECDIR) &&
-		    !(ftsoptions & FTS_NOCHDIR) && fchdir(dotfd)) {
+		    !(ftsoptions & FTS_NOCHDIR) && ios_fchdir_nolock(dotfd)) {
 			warn("chdir");
 			_exit(1);
 		}
@@ -680,8 +683,6 @@ doexec:	if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
 			}
 	}
     pid = waitpid(pid, &status, 0);
-    chdir(pushDirectory);
-    free(pushDirectory);
 	if (plan->flags & F_EXECPLUS) {
 		while (--plan->e_ppos >= plan->e_pbnum)
 			free(plan->e_argv[plan->e_ppos]);
diff --git a/ios_system.m b/ios_system.m
index d6f725a0..5a65949e 100644
--- a/ios_system.m
+++ b/ios_system.m
@@ -592,7 +592,7 @@ void initializeEnvironment() {
         
         NSRange  rSub = NSMakeRange(r1.location + r1.length, r2.location - r1.location - r1.length);
         NSString *variable_string = [argumentString substringWithRange:rSub];
-        const char* variable = getenv([variable_string UTF8String]);
+        const char* variable = ios_getenv([variable_string UTF8String]);
         if (variable) {
             // Okay, so this one exists.
             NSString* replacement_string = [NSString stringWithCString:variable encoding:NSUTF8StringEncoding];
@@ -847,7 +847,7 @@ void __cd_to_dir(NSString *newDir, NSFileManager *fileManager) {
   }
 }
 
-// For some Unix commands that call fchdir (including vim:
+// For some Unix commands that call fchdir (including vim):
 #undef fchdir
 int ios_fchdir(const int fd) {
     NSLog(@"Locking for thread %x in ios_fchdir\n", pthread_self());
@@ -892,6 +892,38 @@ int ios_fchdir(const int fd) {
     return -1;
 }
 
+int ios_fchdir_nolock(const int fd) {
+    // Same function as fchdir, except it does not lock. To be called when resetting directory after fork().
+    while (cleanup_counter > 0) { } // Don't chdir while a command is ending.
+    int result = fchdir(fd);
+    if (result < 0) {
+        return result;
+    }
+    // We managed to change the directory. Update currentSession as well:
+    // Was that allowed?
+    // Allowed "cd" = below miniRoot *or* below localMiniRoot
+    NSFileManager *fileManager = [[NSFileManager alloc] init];
+    NSString* resultDir = [fileManager currentDirectoryPath];
+
+    if (__allowed_cd_to_path(resultDir)) {
+        strcpy(currentSession->previousDirectory, currentSession->currentDir);
+        strcpy(currentSession->currentDir, [resultDir UTF8String]);
+        errno = 0;
+        return 0;
+    }
+    
+    errno = EACCES; // Permission denied
+    // If the user tried to go above the miniRoot, set it to miniRoot
+    if ([miniRoot hasPrefix:resultDir]) {
+        [fileManager changeCurrentDirectoryPath:miniRoot];
+        strcpy(currentSession->currentDir, [miniRoot UTF8String]);
+        strcpy(currentSession->previousDirectory, currentSession->currentDir);
+    } else {
+        // go back to where we were before:
+        [fileManager changeCurrentDirectoryPath:[NSString stringWithCString:currentSession->currentDir encoding:NSUTF8StringEncoding]];
+    }
+    return -1;
+}
 
 int chdir_nolock(const char* path) {
     // Same function as chdir, except it does not lock. To be called from ios_releaseThread*()
@@ -1521,12 +1553,17 @@ int sh_main(int argc, char** argv) {
     // Anything after "sh" that contains an equal sign must be an environment variable. Pass it to ios_setenv.
     while (command[0] != NULL) {
         char* position = strstrquoted(command[0],"=");
-        char* firstSpace = strstrquoted(command[0]," ");
         if (position == NULL) { break; }
+        char* firstSpace = strstrquoted(command[0]," ");
         if (firstSpace < position) { break; }
+        firstSpace = strstrquoted(position," ");
+        if (firstSpace != NULL) { *firstSpace = 0; }
         *position = 0;
         ios_setenv(command[0], position+1, 1);
-        command++;
+        if (firstSpace != NULL) {
+            command[0] = firstSpace + 1;
+        }
+        else { command++; }
     }
     if (command[0] == NULL) {
         argv[0][0] = 'h'; // prevent termination in cleanup_function
@@ -2185,6 +2222,21 @@ int ios_system(const char* inputCmd) {
         }
     } else command = cmd;
     // fprintf(thread_stderr, "Command sent: %s \n", command);
+    // Environment variables before alias expansion:
+    char* commandForParsing = strdup(command);
+    char* commandForParsingFree = commandForParsing;
+    char* firstSpace = strstrquoted(commandForParsing, " ");
+    while (firstSpace != NULL) {
+        *firstSpace = 0;
+        char* equalSign = strchr(commandForParsing, '=');
+        if (equalSign == NULL) break;
+        *equalSign = 0;
+        ios_setenv(commandForParsing, equalSign+1, 1);
+        command += (firstSpace - commandForParsing) + 1;
+        commandForParsing = firstSpace + 1;
+        firstSpace = strstrquoted(commandForParsing, " ");
+    }
+    free(commandForParsingFree);
     // alias expansion *before* input, output and error redirection.
     if ((command[0] != '\\') && (aliasDictionary != nil)) {
         // \command = cancel aliasing, get the original command
@@ -2728,8 +2780,6 @@ int ios_system(const char* inputCmd) {
         NSString* commandName = [NSString stringWithCString:argv[0] encoding:NSUTF8StringEncoding];
         // hasPrefix covers python, python3, python3.9.
         if ([commandName hasPrefix: @"python"]) {
-            // Tell Python that we are running Python3.
-            setenv("PYTHONEXECUTABLE", "python3", 1);
             // Ability to start multiple python3 scripts (required for Jupyter notebooks):
             // start by increasing the number of the interpreter, until we're out.
             int numInterpreter = 0;
@@ -2745,6 +2795,8 @@ int ios_system(const char* inputCmd) {
                     display_alert(@"Too many Python scripts", @"There are too many Python interpreters running at the same time. Try closing some of them.");
                     NSLog(@"%@", @"Too many python scripts running simultaneously. Try closing some notebooks.\n");
                     commandName = @"notAValidCommand";
+                } else {
+                    currentPythonInterpreter = numInterpreter;
                 }
             }
             if ((numInterpreter == 0) && (strlen(argv[0]) > 7)) {
@@ -2986,6 +3038,7 @@ int ios_system(const char* inputCmd) {
   NSString * result = [pathNormalizeArray([path pathComponents], !isAbsolute) componentsJoinedByString: @"/"];
   
   if (!result.length && !isAbsolute) {
+      // Same function as chdir, except it does not lock. To be called from ios_releaseThread*()
     result = @".";
   }
   
@@ -3018,3 +3071,51 @@ int ios_system(const char* inputCmd) {
   
   return pathNormalize(path);
 }
+
+//
+char* ios_getPythonLibraryName() {
+    // Ability to start multiple python3 scripts, expanded for commands that start python3 as a dynamic library.
+    // (mostly vim, right now)
+    // start by increasing the number of the interpreter, until we're out.
+    int numInterpreter = 0;
+    if (currentPythonInterpreter < numPythonInterpreters) {
+        numInterpreter = currentPythonInterpreter;
+        currentPythonInterpreter++;
+    } else {
+        while  (numInterpreter < numPythonInterpreters) {
+            if (PythonIsRunning[numInterpreter] == false) break;
+            numInterpreter++;
+        }
+        if (numInterpreter >= numPythonInterpreters) {
+            // NSLog(@"ios_getPythonLibraryName: returning NULL\n");
+            return NULL;
+        } else {
+            currentPythonInterpreter = numInterpreter;
+        }
+    }
+    char* libraryName = NULL;
+    if ((numInterpreter >= 0) && (numInterpreter < numPythonInterpreters)) {
+        PythonIsRunning[numInterpreter] = true;
+        if (numInterpreter > 0) {
+            libraryName = strdup("pythonA");
+            libraryName[6] = 'A' + (numInterpreter - 1);
+        } else {
+            libraryName = strdup("python3_ios");
+        }
+        // NSLog(@"ios_getPythonLibraryName: returning %s\n", libraryName);
+        return libraryName;
+    }
+    // NSLog(@"ios_getPythonLibraryName: returning NULL\n");
+    return NULL;
+}
+
+void ios_releasePythonLibraryName(char* name) {
+    char libNumber = name[6];
+    if (libNumber == '3') PythonIsRunning[0] = false;
+    else {
+        libNumber -= 'A' - 1;
+        if ((libNumber > 0) && (libNumber < MaxPythonInterpreters))
+            PythonIsRunning[libNumber] = false;
+    }
+    free(name);
+}
diff --git a/shell_cmds/env/env.c b/shell_cmds/env/env.c
index 549e7b68..392cc374 100644
--- a/shell_cmds/env/env.c
+++ b/shell_cmds/env/env.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
 #include <unistd.h>
 
 #include "envopts.h"
+#include <TargetConditionals.h>
 #include "ios_error.h"
 
 extern char **environ;
diff --git a/shell_cmds/printenv/printenv.c b/shell_cmds/printenv/printenv.c
index 8b597fd9..951d9fbd 100644
--- a/shell_cmds/printenv/printenv.c
+++ b/shell_cmds/printenv/printenv.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <TargetConditionals.h>
 #include "ios_error.h"
 
 static void	usage(void);