Exemple #1
0
// 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;
}
Exemple #2
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;
}
Exemple #3
0
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;
}
Exemple #4
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
}
Exemple #5
0
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);
}