Skip to content

Commit 6a9b249

Browse files
committed
Adding mutex locks to prevent process from interfering with each other
at startup/end time.
1 parent 78de960 commit 6a9b249

File tree

4 files changed

+184
-30
lines changed

4 files changed

+184
-30
lines changed

ios_error.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ extern __thread FILE* thread_stderr;
6464
#define getenv ios_getenv
6565
#define setenv ios_setenv
6666
#define unsetenv ios_unsetenv
67+
#define putenv ios_putenv
6768
#define fchdir ios_fchdir
6869

6970
extern int ios_executable(const char* cmd); // is this command part of the "shell" commands?
@@ -79,6 +80,7 @@ extern int ios_dup2(int fd1, int fd2);
7980
extern char * ios_getenv(const char *name);
8081
extern int ios_setenv(const char* variableName, const char* value, int overwrite);
8182
int ios_unsetenv(const char* variableName);
83+
extern int ios_putenv(char *string);
8284
extern char** environmentVariables(pid_t pid);
8385

8486
extern int ios_isatty(int fd);

ios_system.m

Lines changed: 115 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ int ios_getCommandStatus() {
288288
sessionParameters* session;
289289
} functionParameters;
290290

291+
extern pthread_mutex_t pid_mtx;
291292
static void cleanup_function(void* parameters) {
292293
// This function is called when pthread_exit() or ios_kill() is called
293294
functionParameters *p = (functionParameters *) parameters;
@@ -369,6 +370,11 @@ static void cleanup_function(void* parameters) {
369370
mustCloseStderr &= fileno(p->stderr) != fileno(currentSession->stdout);
370371
}
371372
}
373+
// Some programs stop waiting as soon as stdout/stderr close (which makes sense)
374+
if (isLastThread) {
375+
NSLog(@"Locking for thread %x in cleanup_function\n", pthread_self());
376+
pthread_mutex_lock(&pid_mtx); // Avoid multi-lock when several commands end together (for ls | grep)
377+
}
372378
if (mustCloseStderr) {
373379
NSLog(@"Closing stderr (mustCloseStderr): %d \n", fileno(p->stderr));
374380
fclose(p->stderr);
@@ -401,6 +407,9 @@ static void cleanup_function(void* parameters) {
401407
if (currentSession->mainThreadId == pthread_self()) {
402408
currentSession->mainThreadId = 0;
403409
}
410+
if (isLastThread) {
411+
pthread_mutex_unlock(&pid_mtx);
412+
}
404413
}
405414

406415
// Avoir calling crash_handler several times:
@@ -841,20 +850,29 @@ void __cd_to_dir(NSString *newDir, NSFileManager *fileManager) {
841850
// For some Unix commands that call fchdir (including vim:
842851
#undef fchdir
843852
int ios_fchdir(const int fd) {
853+
NSLog(@"Locking for thread %x in ios_fchdir\n", pthread_self());
854+
// We cannot have someone change the current directory while a command is starting or terminating.
855+
// hence the mutex_lock here.
856+
pthread_mutex_lock(&pid_mtx);
844857
int result = fchdir(fd);
845858
if (result < 0) {
859+
NSLog(@"Unlocking for thread %x in ios_fchdir\n", pthread_self());
860+
pthread_mutex_unlock(&pid_mtx);
846861
return result;
847862
}
848863
// We managed to change the directory. Update currentSession as well:
849864
// Was that allowed?
850865
// Allowed "cd" = below miniRoot *or* below localMiniRoot
851866
NSFileManager *fileManager = [[NSFileManager alloc] init];
852867
NSString* resultDir = [fileManager currentDirectoryPath];
868+
NSLog(@"Inside fchdir, path: %s for session: %s\n", resultDir.UTF8String, (char*)currentSession->context);
853869

854870
if (__allowed_cd_to_path(resultDir)) {
855871
strcpy(currentSession->previousDirectory, currentSession->currentDir);
856872
strcpy(currentSession->currentDir, [resultDir UTF8String]);
857873
errno = 0;
874+
NSLog(@"Unlocking for thread %x in ios_fchdir\n", pthread_self());
875+
pthread_mutex_unlock(&pid_mtx);
858876
return 0;
859877
}
860878

@@ -868,30 +886,84 @@ int ios_fchdir(const int fd) {
868886
// go back to where we were before:
869887
[fileManager changeCurrentDirectoryPath:[NSString stringWithCString:currentSession->currentDir encoding:NSUTF8StringEncoding]];
870888
}
889+
NSLog(@"Unlocking for thread %x in ios_fchdir\n", pthread_self());
890+
pthread_mutex_unlock(&pid_mtx);
871891
return -1;
872892
}
873893

874894

895+
int chdir_nolock(const char* path) {
896+
// Same function as chdir, except it does not lock. To be called from ios_releaseThread*()
897+
NSFileManager *fileManager = [[NSFileManager alloc] init];
898+
NSString* newDir = @(path);
899+
BOOL isDir;
900+
// Check for permission and existence:
901+
if (![fileManager fileExistsAtPath:newDir isDirectory:&isDir]) {
902+
errno = ENOENT; // No such file or directory
903+
return -1;
904+
}
905+
if (!isDir) {
906+
errno = ENOTDIR; // Not a directory
907+
return -1;
908+
}
909+
if (![fileManager isReadableFileAtPath:newDir] ||
910+
![fileManager changeCurrentDirectoryPath:newDir]) {
911+
errno = EACCES; // Permission denied
912+
return -1;
913+
}
914+
915+
// We managed to change the directory.
916+
// Was that allowed?
917+
// Allowed "cd" = below miniRoot *or* below localMiniRoot
918+
NSString* resultDir = [fileManager currentDirectoryPath];
919+
920+
if (__allowed_cd_to_path(resultDir)) {
921+
strcpy(currentSession->currentDir, [resultDir UTF8String]);
922+
errno = 0;
923+
return 0;
924+
}
925+
926+
errno = EACCES; // Permission denied
927+
// If the user tried to go above the miniRoot, set it to miniRoot
928+
if ([miniRoot hasPrefix:resultDir]) {
929+
[fileManager changeCurrentDirectoryPath:miniRoot];
930+
strcpy(currentSession->currentDir, [miniRoot UTF8String]);
931+
strcpy(currentSession->previousDirectory, currentSession->currentDir);
932+
} else {
933+
// go back to where we were before:
934+
[fileManager changeCurrentDirectoryPath:[NSString stringWithCString:currentSession->currentDir encoding:NSUTF8StringEncoding]];
935+
}
936+
return -1;
937+
}
875938

876939
// For some Unix commands that call chdir:
877940
// Is also called at the end of the execution of each command
878941
int chdir(const char* path) {
879-
// NSLog(@"Inside chdir, path: %s for session: %s\n", path, (char*)currentSession->context);
942+
NSLog(@"Locking for thread %x in chdir, cd %s, stdin= %d\n", pthread_self(), path, fileno(thread_stdin));
943+
// We cannot have someone change the current directory while a command is starting or terminating.
944+
// hence the mutex_lock here.
945+
pthread_mutex_lock(&pid_mtx);
880946
NSFileManager *fileManager = [[NSFileManager alloc] init];
881947
NSString* newDir = @(path);
882948
BOOL isDir;
883949
// Check for permission and existence:
884950
if (![fileManager fileExistsAtPath:newDir isDirectory:&isDir]) {
885951
errno = ENOENT; // No such file or directory
952+
NSLog(@"Unlocking for thread %x in chdir\n", pthread_self());
953+
pthread_mutex_unlock(&pid_mtx);
886954
return -1;
887955
}
888956
if (!isDir) {
889957
errno = ENOTDIR; // Not a directory
958+
NSLog(@"Unlocking for thread %x in chdir\n", pthread_self());
959+
pthread_mutex_unlock(&pid_mtx);
890960
return -1;
891961
}
892962
if (![fileManager isReadableFileAtPath:newDir] ||
893963
![fileManager changeCurrentDirectoryPath:newDir]) {
894964
errno = EACCES; // Permission denied
965+
NSLog(@"Unlocking for thread %x in chdir\n", pthread_self());
966+
pthread_mutex_unlock(&pid_mtx);
895967
return -1;
896968
}
897969

@@ -902,6 +974,8 @@ int chdir(const char* path) {
902974

903975
if (__allowed_cd_to_path(resultDir)) {
904976
strcpy(currentSession->currentDir, [resultDir UTF8String]);
977+
NSLog(@"Unlocking for thread %x in chdir\n", pthread_self());
978+
pthread_mutex_unlock(&pid_mtx);
905979
errno = 0;
906980
return 0;
907981
}
@@ -916,6 +990,8 @@ int chdir(const char* path) {
916990
// go back to where we were before:
917991
[fileManager changeCurrentDirectoryPath:[NSString stringWithCString:currentSession->currentDir encoding:NSUTF8StringEncoding]];
918992
}
993+
NSLog(@"Unlocking for thread %x in chdir\n", pthread_self());
994+
pthread_mutex_unlock(&pid_mtx);
919995
return -1;
920996
}
921997

@@ -2048,6 +2124,7 @@ static int isRealCommand(const char* fileName) {
20482124
}
20492125

20502126
int ios_system(const char* inputCmd) {
2127+
NSLog(@"command= %s pid= %d\n", inputCmd, ios_currentPid());
20512128
char* command;
20522129
// The names of the files for stdin, stdout, stderr
20532130
char* inputFileName = 0;
@@ -2061,7 +2138,6 @@ int ios_system(const char* inputCmd) {
20612138
char* scriptName = 0; // interpreted commands
20622139
bool sharedErrorOutput = false;
20632140
NSFileManager *fileManager = [[NSFileManager alloc] init];
2064-
NSLog(@"command= %s\n", inputCmd);
20652141
// NSLog(@"ios_system, stdout %d \n", thread_stdout == NULL ? 0 : fileno(thread_stdout));
20662142
// NSLog(@"ios_system, stderr %d \n", thread_stderr == NULL ? 0 : fileno(thread_stderr));
20672143
if (currentSession == NULL) {
@@ -2282,7 +2358,7 @@ int ios_system(const char* inputCmd) {
22822358
// scan until first ">"
22832359
bool appendToFileName = false;
22842360
if (!sharedErrorOutput) {
2285-
// output and append
2361+
// output and append.
22862362
outputFileMarker = strstrquoted(outputFileMarker, ">");
22872363
if (outputFileMarker) {
22882364
if ((strlen(outputFileMarker) > 1) && (outputFileMarker[1] == '>')) { // >>
@@ -2293,7 +2369,8 @@ int ios_system(const char* inputCmd) {
22932369
}
22942370
}
22952371
} else {
2296-
outputFileMarker = NULL;
2372+
if (outputFileName == NULL)
2373+
outputFileMarker = NULL;
22972374
}
22982375
if (outputFileName) {
22992376
while ((outputFileName[0] == ' ') && strlen(outputFileName) > 0) outputFileName++;
@@ -2546,19 +2623,21 @@ int ios_system(const char* inputCmd) {
25462623
cmdIsReal = true;
25472624
NSData *data = [NSData dataWithContentsOfFile:locationName]; // You have the data. Conversion to String probably failed.
25482625
NSString *fileContent = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
2626+
if ((fileContent == nil) && (data.length > 0)) {
2627+
// Conversion to string failed with UTF8. Try with Ascii as a backup:
2628+
fileContent = [[NSString alloc]initWithData:data encoding:NSASCIIStringEncoding];
2629+
}
25492630
NSString* firstLine;
25502631
if (fileContent != nil) {
25512632
NSRange firstLineRange = [fileContent rangeOfString:@"\n"];
2552-
firstLineRange.length = firstLineRange.location;
2633+
if (firstLineRange.length > 0) {
2634+
firstLineRange.length = firstLineRange.location;
2635+
} else {
2636+
firstLineRange.length = fileContent.length;
2637+
}
25532638
firstLineRange.location = 0;
25542639
firstLine = [fileContent substringWithRange:firstLineRange];
25552640
}
2556-
// Detect WebAssembly file signature: '\0asm' (begins with 0, so not a string)
2557-
if ((firstLine == nil) && (data.length >0) && (((char*)data.bytes)[0] == 0)) {
2558-
fileContent = [[NSString alloc]initWithData:data encoding:NSASCIIStringEncoding];
2559-
NSRange signatureRange = NSMakeRange(1, 3);
2560-
firstLine = [fileContent substringWithRange:signatureRange];
2561-
}
25622641
if ([firstLine hasPrefix:@"#!"]) {
25632642
// 1) get script language name
25642643
// The last word of the line is the command. This covers all of the cases encountered:
@@ -2599,19 +2678,27 @@ int ios_system(const char* inputCmd) {
25992678
// TODO: need to loop back if scriptName is itself a file.
26002679
break;
26012680
}
2602-
} else if ([firstLine isEqualToString:@"asm"]) {
2603-
// WebAssembly file, identified by signature:
2604-
// Same code as above, but single command:
2605-
argc += 1;
2606-
argv = (char **)realloc(argv, sizeof(char*) * (argc + 1));
2607-
// Move everything numComponents step up
2608-
for (int i = argc; i >= 1; i--) { argv[i] = argv[i-1]; }
2609-
// Change the location of the file (from "command" to "/actual/full/path/command"):
2610-
// This pointer existed before
2611-
argv[1] = realloc(argv[1], locationName.length + 1);
2612-
strcpy(argv[1], locationName.UTF8String);
2613-
// Copy all arguments without change (except the first):
2614-
argv[0] = strdup("wasm"); // creates new pointer
2681+
} else {
2682+
// Detect WebAssembly file signature: '\0asm' (begins with 0, so not a string)
2683+
if ((data.length >0) && (((char*)data.bytes)[0] == 0)) {
2684+
// fileContent = [[NSString alloc]initWithData:data encoding:NSASCIIStringEncoding];
2685+
NSRange signatureRange = NSMakeRange(1, 3);
2686+
firstLine = [fileContent substringWithRange:signatureRange];
2687+
}
2688+
if ([firstLine isEqualToString:@"asm"]) {
2689+
// WebAssembly file, identified by signature:
2690+
// Same code as above, but single command:
2691+
argc += 1;
2692+
argv = (char **)realloc(argv, sizeof(char*) * (argc + 1));
2693+
// Move everything numComponents step up
2694+
for (int i = argc; i >= 1; i--) { argv[i] = argv[i-1]; }
2695+
// Change the location of the file (from "command" to "/actual/full/path/command"):
2696+
// This pointer existed before
2697+
argv[1] = realloc(argv[1], locationName.length + 1);
2698+
strcpy(argv[1], locationName.UTF8String);
2699+
// Copy all arguments without change (except the first):
2700+
argv[0] = strdup("wasm"); // creates new pointer
2701+
}
26152702
}
26162703
} else {
26172704
cmdIsReal = false;
@@ -2721,14 +2808,16 @@ int ios_system(const char* inputCmd) {
27212808
else handle = dlopen(libraryName.UTF8String, RTLD_LAZY | RTLD_GLOBAL); // commands defined in dynamic library
27222809
if (handle == NULL) {
27232810
NSLog(@"Failed loading %s from %s, cause = %s\n", commandName.UTF8String, libraryName.UTF8String, dlerror());
2724-
if (sideLoading) fprintf(thread_stderr, "Failed loading %s from %s, cause = %s\n", commandName.UTF8String, libraryName.UTF8String, dlerror());
2811+
// if (sideLoading)
2812+
fprintf(thread_stderr, "Failed loading %s from %s, cause = %s\n", commandName.UTF8String, libraryName.UTF8String, dlerror());
27252813
NSString* fileLocation = [[NSBundle mainBundle] pathForResource:libraryName ofType:nil];
27262814
} else {
27272815
NSString* functionName = commandStructure[1];
27282816
function = dlsym(handle, functionName.UTF8String);
27292817
if (function == NULL) {
27302818
NSLog(@"Failed loading %s from %s, cause = %s\n", commandName.UTF8String, libraryName.UTF8String, dlerror());
2731-
if (sideLoading) fprintf(thread_stderr, "Failed loading %s from %s, cause = %s\n", commandName.UTF8String, libraryName.UTF8String, dlerror());
2819+
// if (sideLoading)
2820+
fprintf(thread_stderr, "Failed loading %s from %s, cause = %s\n", functionName.UTF8String, libraryName.UTF8String, dlerror());
27322821
}
27332822
}
27342823
}

ios_system/ios_system.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern int ios_system(const char* inputCmd); // execute this command (executable
2929
extern FILE *ios_popen(const char *command, const char *type); // Execute this command and pipe the result
3030
extern int ios_kill(void); // kill the current running command
3131
extern int ios_killpid(pid_t pid, int sig); // kill the current running command
32+
extern int chdir(const char* path);
3233

3334
extern int ios_isatty(int fd); // test whether a file descriptor refers to a terminal
3435
extern pthread_t ios_getLastThreadId(void);

0 commit comments

Comments
 (0)