// Write the client_state.xml file // int CLIENT_STATE::write_state_file() { MFILE mf; int retval, ret1, ret2, attempt; #ifdef _WIN32 char win_error_msg[4096]; #endif for (attempt=1; attempt<=MAX_STATE_FILE_WRITE_ATTEMPTS; attempt++) { if (attempt > 1) boinc_sleep(1.0); if (log_flags.statefile_debug) { msg_printf(0, MSG_INFO, "[statefile] Writing state file" ); } #ifdef _WIN32 retval = mf.open(STATE_FILE_NEXT, "wc"); #else retval = mf.open(STATE_FILE_NEXT, "w"); #endif if (retval) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { msg_printf(0, MSG_INTERNAL_ERROR, "Can't open %s: %s", STATE_FILE_NEXT, boincerror(retval) ); } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ERR_FOPEN; } MIOFILE miof; miof.init_mfile(&mf); ret1 = write_state(miof); ret2 = mf.close(); if (ret1) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { msg_printf(NULL, MSG_INTERNAL_ERROR, "Couldn't write state file: %s", boincerror(retval) ); } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ret1; } if (ret2) { if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ret2; } // only attempt to rename the current state file if it exists. // if (boinc_file_exists(STATE_FILE_NAME)) { if (boinc_file_exists(STATE_FILE_PREV)) { retval = boinc_delete_file(STATE_FILE_PREV); if (retval) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { #ifdef _WIN32 msg_printf(0, MSG_INFO, "Can't delete previous state file; %s", windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg)) ); #else msg_printf(0, MSG_INFO, "Can't delete previous state file: %s", strerror(errno) ); #endif } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; } } retval = boinc_rename(STATE_FILE_NAME, STATE_FILE_PREV); if (retval) { if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { #ifdef _WIN32 msg_printf(0, MSG_INFO, "Can't rename current state file to previous state file; %s", windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg)) ); #else msg_printf(0, MSG_INFO, "Can't rename current state file to previous state file: %s", strerror(errno) ); #endif } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; } } retval = boinc_rename(STATE_FILE_NEXT, STATE_FILE_NAME); if (log_flags.statefile_debug) { msg_printf(0, MSG_INFO, "[statefile] Done writing state file" ); } if (!retval) break; // Success! if ((attempt == MAX_STATE_FILE_WRITE_ATTEMPTS) || log_flags.statefile_debug) { #ifdef _WIN32 msg_printf(0, MSG_INFO, "rename error: %s", windows_format_error_string(GetLastError(), win_error_msg, sizeof(win_error_msg)) ); #elif defined (__APPLE__) if (log_flags.statefile_debug) { // system() is deprecated in Mac OS 10.10. // Apple says to call posix_spawn instead. callPosixSpawn("ls -al /Library/Application\\ Support/BOINC\\ Data/client*.*"); } #endif } if (attempt < MAX_STATE_FILE_WRITE_ATTEMPTS) continue; return ERR_RENAME; } return 0; }
int main(int argc, char *argv[]) { char pkgPath[MAXPATHLEN]; char postInstallAppPath[MAXPATHLEN]; char temp[MAXPATHLEN], temp2[MAXPATHLEN]; char brand[64], s[256]; char *p; OSStatus err = noErr; Boolean restartNeeded = true; FILE *restartNeededFile; FILE *f; long oldBrandID; if (!check_branding_arrays(temp, sizeof(temp))) { ShowMessage((char *)_("Branding array has too few entries: %s"), temp); return -1; } if (Initialize() != noErr) { return 0; } strncpy(loginName, getenv("USER"), sizeof(loginName)-1); if (loginName[0] == '\0') { ShowMessage((char *)_("Could not get user login name")); return 0; } snprintf(tempDirName, sizeof(tempDirName), "InstallBOINC-%s", loginName); snprintf(temp, sizeof(temp), "/tmp/%s", tempDirName); mkdir(temp, 0777); chmod(temp, 0777); // Needed because mkdir sets permissions restricted by umask (022) snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/BOINC_Installer_Errors", tempDirName); err = callPosixSpawn(temp); snprintf(Catalogs_Dir, sizeof(Catalogs_Dir), "/tmp/%s/BOINC_payload/Library/Application Support/BOINC Data/locale/", tempDirName); // Get the full path to Installer package inside this application's bundle getPathToThisApp(pkgPath, sizeof(pkgPath)); strlcpy(temp, pkgPath, sizeof(temp)); strlcat(pkgPath, "/Contents/Resources/", sizeof(pkgPath)); strlcpy(postInstallAppPath, pkgPath, sizeof(postInstallAppPath)); strlcat(postInstallAppPath, "PostInstall.app", sizeof(postInstallAppPath)); p = strrchr(temp, '/'); // Point to name of this application (e.g., "BOINC Installer.app") if (p == NULL) { p = temp - 1; } else { *p = '\0'; } // Delete any old project auto-attach key file from our temp directory snprintf(temp2, sizeof(temp2), "rm -dfR \"/tmp/%s/%s\"", tempDirName, ACCOUNT_DATA_FILENAME); err = callPosixSpawn(temp2); REPORT_ERROR(err); // Write a file containing the project auto-attach key into our temp // directory because the BOINC Data directory may not yet exist. // PostInstall.app will copy it into the BOINC Data directory laer snprintf(temp2, sizeof(temp2), "%s/%s", temp, ACCOUNT_DATA_FILENAME); if (boinc_file_exists(temp2)) { // If the project server put account_data.txt file in the same // parent directory as this installer, copy it into our temp directory snprintf(temp2, sizeof(temp2), "cp \"%s/%s\" \"/tmp/%s/%s\"", temp, ACCOUNT_DATA_FILENAME, tempDirName, ACCOUNT_DATA_FILENAME); err = callPosixSpawn(temp2); REPORT_ERROR(err); } else { // Create an account_data.txt file containing our // installer's filename and put it in our temp directory snprintf(temp2, sizeof(temp2), "/tmp/%s/%s", tempDirName, ACCOUNT_DATA_FILENAME); f = fopen(temp2, "w"); fputs(p+1, f); fclose(f); } // Write a temp file to tell our PostInstall.app the previous branding, if any oldBrandID = GetOldBrandID(); snprintf(temp, sizeof(temp), "/tmp/%s/OldBranding", tempDirName); f = fopen(temp, "w"); if (!f) { REPORT_ERROR(true); } else { fprintf(f, "BrandId=%ld\n", oldBrandID); fclose(f); } // To allow for branding, assume name of installer package inside bundle corresponds to name of this application strlcpy(brand, p+1, sizeof(brand)); strlcat(pkgPath, p+1, sizeof(pkgPath)); p = strrchr(pkgPath, ' '); // Strip off last space character and everything following if (p) *p = '\0'; p = strrchr(brand, ' '); // Strip off last space character and everything following if (p) *p = '\0'; strlcat(pkgPath, ".pkg", sizeof(pkgPath)); // In the unlikely situation that /tmp has files from an earlier attempt to install // BOINC by a different user, we won't have permission to delete or overwrite them, // so include the current user's name as part of the paths to our temporary files. // Expand the installer package snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/BOINC.pkg", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/expanded_BOINC.pkg", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/PostInstall.app", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); snprintf(temp, sizeof(temp), "rm -f /tmp/%s/BOINC_preferred_languages", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); snprintf(temp, sizeof(temp), "rm -f /tmp/%s/BOINC_restart_flag", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); sprintf(temp, "cp -fpR \"%s\" /tmp/%s/PostInstall.app", postInstallAppPath, tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); sprintf(temp, "pkgutil --expand \"%s\" /tmp/%s/expanded_BOINC.pkg", pkgPath, tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); if (err == noErr) { GetPreferredLanguages(); } if (compareOSVersionTo(10, 6) < 0) { LoadPreferredLanguages(); BringAppToFront(); p = strrchr(brand, ' '); // Strip off last space character and everything following if (p) *p = '\0'; ShowMessage((char *)_("Sorry, this version of %s requires system 10.6 or higher."), brand); snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/BOINC_payload", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); return -1; } snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/BOINC_payload", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); // Remove previous installer package receipt so we can run installer again // (affects only older versions of OS X and fixes a bug in those versions) // "rm -rf /Library/Receipts/GridRepublic.pkg" sprintf(s, "rm -rf \"/Library/Receipts/%s.pkg\"", brand); err = callPosixSpawn (s); REPORT_ERROR(err); restartNeeded = IsRestartNeeded(); // Write a temp file to tell our PostInstall.app whether restart is needed snprintf(temp, sizeof(temp), "/tmp/%s/BOINC_restart_flag", tempDirName); restartNeededFile = fopen(temp, "w"); if (restartNeededFile) { fputs(restartNeeded ? "1\n" : "0\n", restartNeededFile); fclose(restartNeededFile); } if (restartNeeded) { if (err == noErr) { // Change onConclusion="none" to onConclusion="RequireRestart" snprintf(temp, sizeof(temp), "sed -i \".bak\" s/onConclusion=\"none\"/onConclusion=\"RequireRestart\"/g /tmp/%s/expanded_BOINC.pkg/Distribution", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); } if (err == noErr) { snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/expanded_BOINC.pkg/Distribution.bak", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); // Flatten the installer package sprintf(temp, "pkgutil --flatten /tmp/%s/expanded_BOINC.pkg /tmp/%s/%s.pkg", tempDirName, tempDirName, brand); err = callPosixSpawn(temp); REPORT_ERROR(err); } if (err == noErr) { snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/expanded_BOINC.pkg", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); sprintf(temp, "open \"/tmp/%s/%s.pkg\"", tempDirName, brand); err = callPosixSpawn(temp); REPORT_ERROR(err); return err; } } snprintf(temp, sizeof(temp), "rm -dfR /tmp/%s/expanded_BOINC.pkg", tempDirName); err = callPosixSpawn(temp); REPORT_ERROR(err); sprintf(temp, "open \"%s\"", pkgPath); err = callPosixSpawn(temp); REPORT_ERROR(err); return err; }
int main(int argc, char *argv[]) { long brandID = 0; Boolean AddUsers = false; Boolean SetSavers = false; Boolean isBMGroupMember, isBPGroupMember; Boolean saverIsSet = false; passwd *pw; uid_t saved_uid; group grpBOINC_master, *grpBOINC_masterPtr; group grpBOINC_project, *grpBOINC_projectPtr; char bmBuf[32768]; char bpBuf[32768]; char loginName[256]; short index, i; FILE *f; int flag; char *p; char s[1024], buf[1024]; OSStatus err; brandID = GetBrandID(); #ifndef _DEBUG if (getuid() != 0) { printf("This program must be run as root\n"); printUsage(brandID); return 0; } #endif saved_uid = geteuid(); if (argc < 3) { printUsage(brandID); return 0; } if (strcmp(argv[1], "-a") == 0) { AddUsers = true; } else if (strcmp(argv[1], "-s") == 0) { AddUsers = true; SetSavers = true; } else if (strcmp(argv[1], "-r") != 0) { printUsage(brandID); return 0; } printf("\n"); if (!check_branding_arrays(s, sizeof(s))) { printf("Branding array has too few entries: %s\n", s); return -1; } loginName[0] = '\0'; strncpy(loginName, getenv("USER"), sizeof(loginName)-1); err = getgrnam_r("boinc_master", &grpBOINC_master, bmBuf, sizeof(bmBuf), &grpBOINC_masterPtr); if (err) { // Should never happen unless buffer too small puts("getgrnam(\"boinc_master\") failed\n"); return -1; } err = getgrnam_r("boinc_project", &grpBOINC_project, bpBuf, sizeof(bpBuf), &grpBOINC_projectPtr); if (err) { // Should never happen unless buffer too small puts("getgrnam(\"boinc_project\") failed\n"); return -1; } for (index=2; index<argc; index++) { // getpwnam works with either the full / login name (pw->pw_gecos) // or the short / Posix name (pw->pw_name) pw = getpwnam(argv[index]); if ((pw == NULL) || (pw->pw_uid < 501)) { printf("User %s not found.\n\n", argv[index]); continue; } flag = 0; sprintf(s, "dscl . -read \"/Users/%s\" NFSHomeDirectory", pw->pw_name); f = popen(s, "r"); if (!f) { flag = 1; } else { while (PersistentFGets(buf, sizeof(buf), f)) { p = strrchr(buf, ' '); if (p) { if (strstr(p, "/var/empty") != NULL) { flag = 1; break; } } } pclose(f); } if (flag) { sprintf(s, "dscl . -read \"/Users/%s\" UserShell", pw->pw_name); f = popen(s, "r"); if (!f) { flag |= 2; } else { while (PersistentFGets(buf, sizeof(buf), f)) { p = strrchr(buf, ' '); if (p) { if (strstr(p, "/usr/bin/false") != NULL) { flag |= 2; break; } } } pclose(f); } } if (flag == 3) { // if (Home Directory == "/var/empty") && (UserShell == "/usr/bin/false") printf("%s is not a valid user name.\n\n", argv[index]); continue; } printf("%s user %s (/Users/%s)\n", AddUsers? "Adding" : "Removing", pw->pw_gecos, pw->pw_name); isBMGroupMember = false; i = 0; while ((p = grpBOINC_master.gr_mem[i]) != NULL) { // Step through all users in group boinc_master if (strcmp(p, pw->pw_name) == 0) { // Only the short / Posix names are in the list // User is a member of group boinc_master isBMGroupMember = true; break; } ++i; } isBPGroupMember = false; i = 0; while ((p = grpBOINC_project.gr_mem[i]) != NULL) { // Step through all users in group boinc_project if (strcmp(p, pw->pw_name) == 0) { // Only the short / Posix names are in the list // User is a member of group boinc_master isBPGroupMember = true; break; } ++i; } if ((!isBMGroupMember) && AddUsers) { sprintf(s, "dscl . -merge /groups/boinc_master GroupMembership %s", pw->pw_name); callPosixSpawn(s); } if ((!isBPGroupMember) && AddUsers) { sprintf(s, "dscl . -merge /groups/boinc_project GroupMembership %s", pw->pw_name); callPosixSpawn(s); } if (isBMGroupMember && (!AddUsers)) { sprintf(s, "dscl . -delete /Groups/boinc_master GroupMembership %s", pw->pw_name); callPosixSpawn(s); } if (isBPGroupMember && (!AddUsers)) { sprintf(s, "dscl . -delete /Groups/boinc_project GroupMembership %s", pw->pw_name); callPosixSpawn(s); } if (!AddUsers) { // Delete per-user BOINC Manager and screensaver files sprintf(s, "rm -fR \"/Users/%s/Library/Application Support/BOINC\"", pw->pw_name); callPosixSpawn (s); } // Set or remove login item for this user bool useOSASript = false; if ((compareOSVersionTo(10, 13) < 0) || (strcmp(loginName, pw->pw_name) == 0) || (strcmp(loginName, pw->pw_gecos) == 0)) { useOSASript = true; } #if USE_OSASCRIPT_FOR_ALL_LOGGED_IN_USERS if (! useOSASript) { useOSASript = IsUserLoggedIn(pw->pw_name); } #endif if (useOSASript) { snprintf(s, sizeof(s), "/Users/%s/Library/LaunchAgents/edu.berkeley.boinc.plist", pw->pw_name); boinc_delete_file(s); SetLoginItemOSAScript(brandID, !AddUsers, pw->pw_name); } else { SetLoginItemLaunchAgent(brandID, !AddUsers, pw); } saverIsSet = false; err = GetCurrentScreenSaverSelection(pw, s, sizeof(s) -1); #if VERBOSE fprintf(stderr, "Current Screensaver Selection for user %s is: \"%s\"\n", pw->pw_name, s); #endif if (err == noErr) { if (!strcmp(s, saverName[brandID])) { saverIsSet = true; } } if (SetSavers) { if (saverIsSet) { printf("Screensaver already set to %s for user %s (/Users/%s)\n", saverName[brandID], pw->pw_gecos, pw->pw_name); } else { printf("Setting screensaver to %s for user %s (/Users/%s)\n", saverName[brandID], pw->pw_gecos, pw->pw_name); } } if ((!saverIsSet) && SetSavers) { seteuid(pw->pw_uid); // Temporarily set effective uid to this user sprintf(s, "/Library/Screen Savers/%s.saver", saverName[brandID]); err = SetScreenSaverSelection(pw, saverName[brandID], s, 0); #if VERBOSE fprintf(stderr, "SetScreenSaverSelection for user %s (uid %d) to \"%s\" returned error %d\n", pw->pw_name, geteuid(), saverName[brandID], err); #endif seteuid(saved_uid); // Set effective uid back to privileged user // This seems to work also: // sprintf(buf, "su -l \"%s\" -c 'defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName \"%s\" path \"%s\ type 0'", pw->pw_name, saverName[brandID], s); // callPosixSpawn(s); } if (saverIsSet && (!AddUsers)) { printf("Setting screensaver to Flurry for user %s (/Users/%s)\n", pw->pw_gecos, pw->pw_name); seteuid(pw->pw_uid); // Temporarily set effective uid to this user err = SetScreenSaverSelection(pw, "Flurry", "/System/Library/Screen Savers/Flurry.saver", 0); #if VERBOSE fprintf(stderr, "SetScreenSaverSelection for user %s (%d) to Flurry returned error %d\n", pw->pw_name, geteuid(), err); #endif seteuid(saved_uid); // Set effective uid back to privileged user } seteuid(saved_uid); // Set effective uid back to privileged user printf("\n"); } printf("WARNING: Changes may require a system restart to take effect.\n"); return 0; }
// 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 }
Boolean SetLoginItemOSAScript(long brandID, Boolean deleteLogInItem, char *userName) { int i, j; char cmd[2048]; char systemEventsPath[1024]; pid_t systemEventsPID; OSErr err = 0, err2 = 0; #if USE_OSASCRIPT_FOR_ALL_LOGGED_IN_USERS // NOTE: It may not be necessary to kill and relaunch the // System Events application for each logged in user under High Sierra Boolean isHighSierraOrLater = (compareOSVersionTo(10, 13) >= 0); #endif #if VERBOSE fprintf(stderr, "Adjusting login items for user %s\n", userName); fflush(stderr); #endif // We must launch the System Events application for the target user err = noErr; systemEventsPath[0] = '\0'; err = GetPathToAppFromID(kSystemEventsCreator, kSystemEventsBundleID, systemEventsPath, sizeof(systemEventsPath)); #if VERBOSE if (err == noErr) { fprintf(stderr, "SystemEvents is at %s\n", systemEventsPath); } else { fprintf(stderr, "GetPathToAppFromID(kSystemEventsCreator, kSystemEventsBundleID) returned error %d ", (int) err); } #endif if (err == noErr) { // Find SystemEvents process. If found, quit it in case // it is running under a different user. #if VERBOSE fprintf(stderr, "Telling System Events to quit (at start of SetLoginItemOSAScript)\n"); fflush(stderr); #endif systemEventsPID = FindProcessPID(systemEventsAppName, 0); if (systemEventsPID != 0) { err = kill(systemEventsPID, SIGKILL); } #if VERBOSE if (err != noErr) { fprintf(stderr, "(systemEventsPID, SIGKILL) returned error %d \n", (int) err); fflush(stderr); } #endif // Wait for the process to be gone for (i=0; i<50; ++i) { // 5 seconds max delay SleepSeconds(0.1); // 1/10 second systemEventsPID = FindProcessPID(systemEventsAppName, 0); if (systemEventsPID == 0) break; } if (i >= 50) { #if VERBOSE fprintf(stderr, "Failed to make System Events quit\n"); fflush(stderr); #endif err = noErr; goto cleanupSystemEvents; } sleep(4); } if (systemEventsPath[0] != '\0') { #if VERBOSE fprintf(stderr, "Launching SystemEvents for user %s\n", userName); fflush(stderr); #endif for (j=0; j<5; ++j) { sprintf(cmd, "sudo -u \"%s\" -b \"%s/Contents/MacOS/System Events\" &", userName, systemEventsPath); err = callPosixSpawn(cmd); #if VERBOSE if (err) { fprintf(stderr, "Command: %s returned error %d (try %d of 5)\n", cmd, (int) err, j); fflush(stderr); } #endif // Wait for the process to start for (i=0; i<50; ++i) { // 5 seconds max delay SleepSeconds(0.1); // 1/10 second systemEventsPID = FindProcessPID(systemEventsAppName, 0); if (systemEventsPID != 0) break; } if (i < 50) break; // Exit j loop on success } if (j >= 5) { #if VERBOSE fprintf(stderr, "Failed to launch System Events for user %s\n", userName); fflush(stderr); #endif err = noErr; goto cleanupSystemEvents; } } sleep(2); #if VERBOSE fprintf(stderr, "Deleting any login items containing %s for user %s\n", appName[brandID], userName); fflush(stderr); #endif #if USE_OSASCRIPT_FOR_ALL_LOGGED_IN_USERS if (isHighSierraOrLater) { sprintf(cmd, "su -l \"%s\" -c 'osascript -e \"tell application \\\"System Events\\\" to delete login item \\\"%s\\\"\"'", userName, appName[i]); } else #endif { sprintf(cmd, "sudo -u \"%s\" osascript -e 'tell application \"System Events\" to delete login item \"%s\"'", userName, appName[i]); } err = callPosixSpawn(cmd); #if VERBOSE if (err) { fprintf(stderr, "Command: %s\n", cmd); fprintf(stderr, "Delete login item containing %s returned error %d\n", appName[brandID], err); fflush(stderr); } #endif if (deleteLogInItem) { err = noErr; goto cleanupSystemEvents; } #if VERBOSE fprintf(stderr, "Making new login item %s for user %s\n", appName[brandID], userName); fflush(stderr); #endif #if USE_OSASCRIPT_FOR_ALL_LOGGED_IN_USERS if (isHighSierraOrLater) { sprintf(cmd, "su -l \"%s\" -c 'osascript -e \"tell application \\\"System Events\\\" to make new login item at end with properties {path:\\\"%s\\\", hidden:true, name:\\\"%s\\\"}\"'", userName, appPath[brandID], appName[brandID]); } else #endif { sprintf(cmd, "sudo -u \"%s\" osascript -e 'tell application \"System Events\" to make new login item at end with properties {path:\"%s\", hidden:true, name:\"%s\"}'", userName, appPath[brandID], appName[brandID]); } err = callPosixSpawn(cmd); #if VERBOSE if (err) { fprintf(stderr, "Command: %s\n", cmd); printf("[Make login item for %s returned error %d\n", appPath[brandID], err); } #endif fflush(stderr); cleanupSystemEvents: // Clean up in case this was our last user #if VERBOSE fprintf(stderr, "Telling System Events to quit (at end of SetLoginItemOSAScript)\n"); fflush(stderr); #endif systemEventsPID = FindProcessPID(systemEventsAppName, 0); err2 = noErr; if (systemEventsPID != 0) { err2 = kill(systemEventsPID, SIGKILL); } #if VERBOSE if (err2 != noErr) { fprintf(stderr, "kill(systemEventsPID, SIGKILL) returned error %d \n", (int) err2); fflush(stderr); } #endif // Wait for the process to be gone for (i=0; i<50; ++i) { // 5 seconds max delay SleepSeconds(0.1); // 1/10 second systemEventsPID = FindProcessPID(systemEventsAppName, 0); if (systemEventsPID == 0) break; } #if VERBOSE if (i >= 50) { fprintf(stderr, "Failed to make System Events quit\n"); fflush(stderr); } #endif sleep(4); return (err == noErr); }