int callPosixSpawn(const char *cmdline) { char command[1024]; char progName[1024]; char progPath[MAXPATHLEN]; char* argv[100]; int argc = 0; char *p; pid_t thePid = 0; int result = 0; int status = 0; extern char **environ; // Make a copy of cmdline because parse_posix_spawn_command_line modifies it strlcpy(command, cmdline, sizeof(command)); argc = parse_posic_spawn_command_line(const_cast<char*>(command), argv); strlcpy(progPath, argv[0], sizeof(progPath)); strlcpy(progName, argv[0], sizeof(progName)); p = strrchr(progName, '/'); if (p) { argv[0] = p+1; } else { argv[0] = progName; } #if VERBOSE_TEST print_to_log_file("***********"); for (int i=0; i<argc; ++i) { print_to_log_file("argv[%d]=%s", i, argv[i]); } print_to_log_file("***********\n"); #endif errno = 0; result = posix_spawnp(&thePid, progPath, NULL, NULL, argv, environ); #if VERBOSE_TEST print_to_log_file("callPosixSpawn command: %s", cmdline); print_to_log_file("callPosixSpawn: posix_spawnp returned %d: %s", result, strerror(result)); #endif if (result) { return result; } // CAF int val = waitpid(thePid, &status, WUNTRACED); // CAF if (val < 0) printf("first waitpid returned %d\n", val); if (status != 0) { #if VERBOSE_TEST print_to_log_file("waitpid() returned status=%d", status); #endif result = status; } else { if (WIFEXITED(status)) { result = WEXITSTATUS(status); if (result == 1) { #if VERBOSE_TEST print_to_log_file("WEXITSTATUS(status) returned 1, errno=%d: %s", errno, strerror(errno)); #endif result = errno; } #if VERBOSE_TEST else if (result) { print_to_log_file("WEXITSTATUS(status) returned %d", result); } #endif } // end if (WIFEXITED(status)) else } // end if waitpid returned 0 sstaus else return result; }
int main(int argc, char** argv) { passwd *pw; group *grp; char user_name[256], group_name[256]; char gfx_app_path[MAXPATHLEN], resolved_path[MAXPATHLEN]; char *BOINCDatSlotsPath = "/Library/Application Support/BOINC Data/slots/"; int retval; int pid; if (argc < 2) return EINVAL; strlcpy(user_name, "boinc_project", sizeof(user_name)); strlcpy(group_name, user_name, sizeof(group_name)); #if 0 // For debugging only // Allow debugging without running as user or group boinc_project pw = getpwuid(getuid()); if (pw) strlcpy(user_name, pw->pw_name, sizeof(user_name)); grp = getgrgid(getgid()); if (grp) strlcpy(group_name, grp->gr_gid, sizeof(group_name)); #endif // We are running setuid root, so setgid() sets real group ID, // effective group ID and saved set_group-ID for this process grp = getgrnam(group_name); if (grp) setgid(grp->gr_gid); // We are running setuid root, so setuid() sets real user ID, // effective user ID and saved set_user-ID for this process pw = getpwnam(user_name); if (pw) setuid(pw->pw_uid); // NOTE: call print_to_log_file only after switching user and group #if 0 // For debugging only char current_dir[MAXPATHLEN]; getcwd( current_dir, sizeof(current_dir)); print_to_log_file( "current directory = %s", current_dir); for (int i=0; i<argc; i++) { print_to_log_file("switcher arg %d: %s", i, argv[i]); } #endif if (strcmp(argv[1], "-default_gfx") == 0) { strlcpy(resolved_path, "/Library/Application Support/BOINC Data/boincscr", sizeof(resolved_path)); argv[2] = resolved_path; #if 0 // For debugging only for (int i=2; i<argc; i++) { print_to_log_file("calling execv with arg %d: %s", i-2, argv[i]); } #endif // For unknown reasons, the graphics application exits with // "RegisterProcess failed (error = -50)" unless we pass its // full path twice in the argument list to execv. execv(resolved_path, argv+2); // If we got here execv failed fprintf(stderr, "Process creation (%s) failed: errno=%d\n", resolved_path, errno); return errno; } if (strcmp(argv[1], "-launch_gfx") == 0) { strlcpy(gfx_app_path, BOINCDatSlotsPath, sizeof(gfx_app_path)); strlcat(gfx_app_path, argv[2], sizeof(gfx_app_path)); strlcat(gfx_app_path, "/", sizeof(gfx_app_path)); strlcat(gfx_app_path, GRAPHICS_APP_FILENAME, sizeof(gfx_app_path)); retval = boinc_resolve_filename(gfx_app_path, resolved_path, sizeof(resolved_path)); if (retval) return retval; argv[2] = resolved_path; #if 0 // For debugging only for (int i=2; i<argc; i++) { print_to_log_file("calling execv with arg %d: %s", i-2, argv[i]); } #endif // For unknown reasons, the graphics application exits with // "RegisterProcess failed (error = -50)" unless we pass its // full path twice in the argument list to execv. execv(resolved_path, argv+2); // If we got here execv failed fprintf(stderr, "Process creation (%s) failed: errno=%d\n", resolved_path, errno); return errno; } if (strcmp(argv[1], "-kill_gfx") == 0) { pid = atoi(argv[2]); if (! pid) return EINVAL; if ( kill(pid, SIGKILL)) { #if 0 // For debugging only print_to_log_file("kill(%d, SIGKILL) returned error %d", pid, errno); #endif return errno; } return 0; } return EINVAL; // Unknown command }
// Because language preferences are set on a per-user basis, we // must get the preferred languages while set to the current // user, before the Apple Installer switches us to root. // So we get the preferred languages here and write them to a // temporary file to be retrieved by our PostInstall app. static void GetPreferredLanguages() { DIR *dirp; struct dirent *dp; char temp[MAXPATHLEN]; char searchPath[MAXPATHLEN]; char savedWD[MAXPATHLEN]; struct stat sbuf; CFMutableArrayRef supportedLanguages; CFStringRef aLanguage; char shortLanguage[32]; CFArrayRef preferredLanguages; int i, j, k; char * language; char *uscore; FILE *f; getcwd(savedWD, sizeof(savedWD)); snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/BOINC_payload", tempDirName); callPosixSpawn(temp); snprintf(temp, sizeof(temp), "/tmp/%s/BOINC_payload", tempDirName); mkdir(temp, 0777); chmod(temp, 0777); // Needed because mkdir sets permissions restricted by umask (022) chdir(temp); snprintf(temp, sizeof(temp), "cpio -i -I /tmp/%s/expanded_BOINC.pkg/BOINC.pkg/Payload", tempDirName); callPosixSpawn(temp); chdir(savedWD); // Create an array of all our supported languages supportedLanguages = CFArrayCreateMutable(kCFAllocatorDefault, 100, &kCFTypeArrayCallBacks); aLanguage = CFStringCreateWithCString(NULL, "en", kCFStringEncodingMacRoman); CFArrayAppendValue(supportedLanguages, aLanguage); CFRelease(aLanguage); aLanguage = NULL; dirp = opendir(Catalogs_Dir); if (!dirp) { REPORT_ERROR(true); goto cleanup; } while (true) { dp = readdir(dirp); if (dp == NULL) break; // End of list if (dp->d_name[0] == '.') continue; // Ignore names beginning with '.' strlcpy(searchPath, Catalogs_Dir, sizeof(searchPath)); strlcat(searchPath, dp->d_name, sizeof(searchPath)); strlcat(searchPath, "/", sizeof(searchPath)); strlcat(searchPath, Catalog_Name, sizeof(searchPath)); strlcat(searchPath, ".mo", sizeof(searchPath)); if (stat(searchPath, &sbuf) != 0) continue; // printf("Adding %s to supportedLanguages array\n", dp->d_name); aLanguage = CFStringCreateWithCString(NULL, dp->d_name, kCFStringEncodingMacRoman); CFArrayAppendValue(supportedLanguages, aLanguage); CFRelease(aLanguage); aLanguage = NULL; // If it has a region code ("it_IT") also try without region code ("it") // TODO: Find a more general solution strlcpy(shortLanguage, dp->d_name, sizeof(shortLanguage)); uscore = strchr(shortLanguage, '_'); if (uscore) { *uscore = '\0'; aLanguage = CFStringCreateWithCString(NULL, shortLanguage, kCFStringEncodingMacRoman); CFArrayAppendValue(supportedLanguages, aLanguage); CFRelease(aLanguage); aLanguage = NULL; } } closedir(dirp); // Write a temp file to tell our PostInstall.app our preferred languages snprintf(temp, sizeof(temp), "/tmp/%s/BOINC_preferred_languages", tempDirName); f = fopen(temp, "w"); if (!f) { REPORT_ERROR(true); goto cleanup; } for (i=0; i<MAX_LANGUAGES_TO_TRY; ++i) { preferredLanguages = CFBundleCopyLocalizationsForPreferences(supportedLanguages, NULL ); #if 0 // For testing int c = CFArrayGetCount(preferredLanguages); for (k=0; k<c; ++k) { CFStringRef s = (CFStringRef)CFArrayGetValueAtIndex(preferredLanguages, k); printf("Preferred language %u is %s\n", k, CFStringGetCStringPtr(s, kCFStringEncodingMacRoman)); } #endif for (j=0; j<CFArrayGetCount(preferredLanguages); ++j) { aLanguage = (CFStringRef)CFArrayGetValueAtIndex(preferredLanguages, j); language = (char *)CFStringGetCStringPtr(aLanguage, kCFStringEncodingMacRoman); if (language == NULL) { if (CFStringGetCString(aLanguage, shortLanguage, sizeof(shortLanguage), kCFStringEncodingMacRoman)) { language = shortLanguage; } } if (f && language) { fprintf(f, "%s\n", language); #if CREATE_LOG print_to_log_file("Adding language: %s\n", language); #endif } // Remove all copies of this language from our list of supported languages // so we can get the next preferred language in order of priority for (k=CFArrayGetCount(supportedLanguages)-1; k>=0; --k) { if (CFStringCompare(aLanguage, (CFStringRef)CFArrayGetValueAtIndex(supportedLanguages, k), 0) == kCFCompareEqualTo) { CFArrayRemoveValueAtIndex(supportedLanguages, k); } } // Since the original strings are English, no // further translation is needed for language en. if (language) { if (!strcmp(language, "en")) { fclose(f); CFRelease(preferredLanguages); preferredLanguages = NULL; goto cleanup; } } } CFRelease(preferredLanguages); preferredLanguages = NULL; } if (f) { fprintf(f, "en\n"); fclose(f); } cleanup: CFArrayRemoveAllValues(supportedLanguages); CFRelease(supportedLanguages); supportedLanguages = NULL; #if CREATE_LOG print_to_log_file("Exiting GetPreferredLanguages"); #endif }