int main(int argc, char** argv) { if(argc < 4) { PrintUsage(stdout); return 0; } /* <argv parsing> */ /* Parse argument: mountpoint (CFString) */ /*CFStringRef mountpoint = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8); */ /* Parse argument: mountpointRaw (char*) */ char *mountpointRaw = argv[1]; /* Parse argument: timeout (double) */ double timeout; { CFStringRef timeoutString = CFStringCreateWithCString(kCFAllocatorDefault, argv[2], kCFStringEncodingUTF8); timeout = CFStringGetDoubleValue(timeoutString); CFRelease(timeoutString); if(timeout == 0.0) { fprintf(stdout, "Invalid argument: timeout (\"%s\"", argv[2]); return -1; } } /* Parse argument: mount_command */ const char *mount_command = argv[3]; /* </argv parsing> */ CFNotificationCenterRef centerRef; CFStringRef notificationObjectName = CFSTR(FUSE_LISTEN_OBJECT); CFStringRef notificationName = CFSTR(FUSE_MOUNT_NOTIFICATION_NAME); CFRunLoopRef crl; if(DEBUGMODE) { DEBUG("Testing NotificationCallback...\n"); NotificationCallback(NULL, NULL, notificationObjectName, NULL, NULL); DEBUG("Test completed. Adding observer...\n"); } centerRef = CFNotificationCenterGetDistributedCenter(); crl = CFRunLoopGetCurrent(); /* Think. Will the child process also be an observer? I don't think so... */ CFNotificationCenterAddObserver(centerRef, NULL, NotificationCallback, notificationName, notificationObjectName, CFNotificationSuspensionBehaviorDrop); int forkRetval = fork(); if(forkRetval == -1) { fprintf(stderr, "Could not fork!\n"); return -1; } else if(forkRetval != 0) { // Parent process int childProcessPID = forkRetval; int waitpid_status = 0; DEBUG("Waiting for PID %d...\n", childProcessPID); int waitpidres = waitpid(childProcessPID, &waitpid_status, 0); if(waitpidres == childProcessPID) { if(!WIFEXITED(waitpid_status)) { DEBUG("Child process did not exit cleanly! Returning -1."); return -1; } int retval = WEXITSTATUS(waitpid_status); DEBUG("PID %d returned with exit code: %d Exiting fuse_wait with this exit code...\n", childProcessPID, retval); if(retval != 0) { DEBUG("Exit value indicates an error while executing mount command. Returning without\n"); DEBUG("waiting for notification.\n"); DEBUG("Returning retval: %d\n", retval); return retval; } } else { DEBUG("Abnormal termination of process %d. :( waitpid returned: %d\n", childProcessPID, waitpidres); return -1; } DEBUG("Running run loop a long time...\n"); CFStringRef mountPathSnapshot = NULL; while(mountPathSnapshot == NULL) { int crlrimRetval = CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, true); DEBUG("Exited from run loop. Let's find out why... crlrimRetval: %d (handled: %d)\n", crlrimRetval, kCFRunLoopRunHandledSource); mountPathSnapshot = mountPath; // Might have been modified during run loop. if(crlrimRetval != kCFRunLoopRunHandledSource) { fprintf(stderr, "Did not receive a signal within %f seconds. Exiting...\n", timeout); break; } else if(mountPathSnapshot != NULL) { DEBUG("mountPathSnapshot: %X\n", (int)mountPathSnapshot); int mountPathUTF8Length = CFStringGetLength(mountPath) + 1; // null terminator char *mountPathUTF8 = malloc(mountPathUTF8Length); memset(mountPathUTF8, 0, mountPathUTF8Length); GetCorruptedMacFUSEStringAsUTF8(mountPath, mountPathUTF8, mountPathUTF8Length); char *canonicalMountPath = malloc(PATH_MAX); char *canonicalMountpoint = malloc(PATH_MAX); memset(canonicalMountPath, 0, PATH_MAX); memset(canonicalMountpoint, 0, PATH_MAX); realpath(mountPathUTF8, canonicalMountPath); realpath(mountpointRaw, canonicalMountpoint); int cmpres = strncmp(canonicalMountPath, canonicalMountpoint, PATH_MAX); if(cmpres != 0) { if(DEBUGMODE) { DEBUG("Strings NOT equal. cmpres=%d\n", cmpres); DEBUG("mountPath (UTF-8): \"%s\"\n", canonicalMountPath); DEBUG("mountpoint (UTF-8): \"%s\"\n", canonicalMountpoint); } mountPathSnapshot = NULL; } else DEBUG("Mounter has signaled! Great success!\n"); free(mountPathUTF8); free(canonicalMountPath); free(canonicalMountpoint); } //CFRunLoopRun(); } DEBUG("Run loop done.\n"); if(mountPath != NULL) CFRelease(mountPath); return 0; // We have previously checked that the return value from the child process is 0. We can't get here if it isn't. } else { // forkRetval == 0 // Child process const int childargc = argc-3; char *childargv[childargc+1]; childargv[childargc] = NULL; // Null terminated int i; for(i = 0; i < childargc; ++i) childargv[i] = argv[i+(argc-childargc)]; if(DEBUGMODE) { DEBUG("Contents of argv:\n"); for(i = 0; i < argc; ++i) DEBUG(" argv[%i]: \"%s\"\n", i, argv[i]); DEBUG("Contents of childargv:\n"); for(i = 0; i < childargc; ++i) DEBUG(" childargv[%i]: \"%s\"\n", i, childargv[i]); } execvp(mount_command, childargv); fprintf(stderr, "Could not execute %s!\n", argv[3]); return -1; } }
int main(int argc, char** argv) { LOG_DEBUG("[Debug messages enabled]\n"); if(argc < 4) { PrintUsage(stdout); return 0; } /* <argv parsing> */ /* Parse argument: mountpoint (CFString) */ /*CFStringRef mountpoint = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8); */ /* Parse argument: mountpointRaw (char*) */ char *mountpointRaw = argv[1]; /* Parse argument: timeout (double) */ double timeout; { CFStringRef timeoutString = CFStringCreateWithCString(kCFAllocatorDefault, argv[2], kCFStringEncodingUTF8); timeout = CFStringGetDoubleValue(timeoutString); CFRelease(timeoutString); if(timeout == 0.0) { fprintf(stdout, "Invalid argument: timeout (\"%s\")\n", argv[2]); return -1; } } /* Parse argument: mount_command */ const char *mount_command = argv[3]; /* </argv parsing> */ CFNotificationCenterRef centerRef; CFStringRef notificationObjectName = CFSTR(FUSE_LISTEN_OBJECT); CFStringRef notificationName = CFSTR(FUSE_MOUNT_NOTIFICATION_NAME); //CFRunLoopRef runLoop; if(DEBUGMODE) { LOG_DEBUG("Testing NotificationCallback...\n"); NotificationCallback(NULL, NULL, notificationObjectName, NULL, NULL); LOG_DEBUG("Test completed. Adding observer...\n"); } centerRef = CFNotificationCenterGetDistributedCenter(); //runLoop = CFRunLoopGetCurrent(); /* * We need to add ourselves as an observer before the fork, in case the forked * process outruns us. * * Will the child process also be an observer? Possibly, but even if that is * the case, it shouldn't seem to make any practical difference (we never * enter a CFRunLoop in the child process, at least not before execvp). */ CFNotificationCenterAddObserver(centerRef, NULL, NotificationCallback, notificationName, notificationObjectName, CFNotificationSuspensionBehaviorDrop); int forkRetval = fork(); if(forkRetval == -1) { fprintf(stderr, "Could not fork!\n"); return -1; } else if(forkRetval != 0) { // Parent process int childProcessPID = forkRetval; int waitpid_status = 0; LOG_DEBUG("Waiting for PID %d...\n", childProcessPID); int waitpidres = waitpid(childProcessPID, &waitpid_status, 0); if(waitpidres == childProcessPID) { if(!WIFEXITED(waitpid_status)) { LOG_DEBUG("Child process did not exit cleanly! Returning -1."); return -1; } int retval = WEXITSTATUS(waitpid_status); LOG_DEBUG("PID %d returned with exit code: %d Exiting fuse_wait with this exit code...\n", childProcessPID, retval); if(retval != 0) { LOG_DEBUG("Exit value indicates an error while executing mount command. Returning without\n"); LOG_DEBUG("waiting for notification.\n"); LOG_DEBUG("Returning retval: %d\n", retval); return retval; } } else { LOG_DEBUG("Abnormal termination of process %d. waitpid returned: %d\n", childProcessPID, waitpidres); return -1; } LOG_DEBUG("Running run loop a long time...\n"); CFStringRef mountPathSnapshot = NULL; while(mountPathSnapshot == NULL) { #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 int crlrimRetval = CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, true); LOG_DEBUG("Exited from run loop. Let's find out why... crlrimRetval: %d " "(handled: %d)\n", crlrimRetval, kCFRunLoopRunHandledSource); #else CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, true); LOG_DEBUG("Exited from run loop. Let's find out why.\n"); #endif mountPathSnapshot = mountPath; // Might have been modified during RunLoop. #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 if(crlrimRetval != kCFRunLoopRunHandledSource) { fprintf(stderr, "Did not receive a signal within %f seconds. " "Exiting...\n", timeout); return -2; } #endif if(mountPathSnapshot != NULL) { LOG_DEBUG("mountPathSnapshot: %p\n", mountPathSnapshot); /* * Convert the CFString that we got back from the CFNotificationCenter * into UTF-8 data. (We assume that UTF-8 is the encoding used by the * system, which is true in Mac OS X.) */ CFDataRef utf8Data = CFStringCreateExternalRepresentation(NULL, mountPath, kCFStringEncodingUTF8, 0); if(utf8Data != NULL) { /* * Put the UTF-8 data in a NULL-terminated C-string. */ size_t mountPathUTF8Length = CFDataGetLength(utf8Data) + 1; char *mountPathUTF8 = calloc(1, mountPathUTF8Length); CFDataGetBytes(utf8Data, CFRangeMake(0, mountPathUTF8Length - 1), (unsigned char*) mountPathUTF8); //int mountPathUTF8Length = CFStringGetLength(mountPath) + 1; // null terminator //char *mountPathUTF8 = malloc(mountPathUTF8Length); //memset(mountPathUTF8, 0, mountPathUTF8Length); //GetCorruptedMacFUSEStringAsUTF8(mountPath, mountPathUTF8, mountPathUTF8Length); /* * Canonicalize the two paths, in case one of the pathnames contain * symbolic links, but not the other. */ char *canonicalMountPath = malloc(PATH_MAX); char *canonicalMountpoint = malloc(PATH_MAX); memset(canonicalMountPath, 0, PATH_MAX); memset(canonicalMountpoint, 0, PATH_MAX); realpath(mountPathUTF8, canonicalMountPath); realpath(mountpointRaw, canonicalMountpoint); /* * Finally, compare the two paths for equality. */ int cmpres = strncmp(canonicalMountPath, canonicalMountpoint, PATH_MAX); if(cmpres != 0) { LOG_DEBUG("Strings NOT equal. cmpres=%d\n", cmpres); LOG_DEBUG("mountPath (UTF-8): \"%s\"\n", canonicalMountPath); LOG_DEBUG("mountpoint (UTF-8): \"%s\"\n", canonicalMountpoint); mountPathSnapshot = NULL; } else LOG_DEBUG("Recieved a signal for the mount point.\n"); free(mountPathUTF8); free(canonicalMountPath); free(canonicalMountpoint); } CFRelease(utf8Data); } } LOG_DEBUG("Run loop done.\n"); if(mountPath != NULL) CFRelease(mountPath); return 0; // We have previously checked that the return value from the child process is 0. We can't get here if it isn't. } else { // forkRetval == 0 // Child process const int childargc = argc-3; char *childargv[childargc+1]; childargv[childargc] = NULL; // Null terminated int i; for(i = 0; i < childargc; ++i) childargv[i] = argv[i+(argc-childargc)]; LOG_DEBUG("Contents of argv:\n"); for(i = 0; i < argc; ++i) LOG_DEBUG(" argv[%i]: \"%s\"\n", i, argv[i]); LOG_DEBUG("Contents of childargv:\n"); for(i = 0; i < childargc; ++i) LOG_DEBUG(" childargv[%i]: \"%s\"\n", i, childargv[i]); execvp(mount_command, childargv); fprintf(stderr, "Could not execute %s!\n", argv[3]); return -1; } }