Example #1
0
// After installation has completed, delete the installer receipt.  
// If we don't need to logout the user, also launch BOINC Manager.
int DeleteReceipt()
{
    ProcessSerialNumber     installerPSN;
    long                    brandID = 0;
    int                     i;
    pid_t                   installerPID = 0;
    OSStatus                err;
    int                     finalInstallAction;
    FSRef                   fileRef;
    char                    s[256];
    struct stat             sbuf;
    OSStatus                err_fsref;

    Initialize();
    err = CheckLogoutRequirement(&finalInstallAction);

    err = FindProcess ('APPL', 'xins', &installerPSN);
    if (err == noErr)
        err = GetProcessPID(&installerPSN , &installerPID);

   // Launch BOINC Manager when user closes installer or after 15 seconds
    for (i=0; i<15; i++) { // Wait 15 seconds max for installer to quit
        sleep (1);
        if (err == noErr)
            if (FindProcessPID(NULL, installerPID) == 0)
                break;
    }

    brandID = GetBrandID();

    // Remove installer package receipt so we can run installer again if needed to fix permissions
    // "rm -rf /Library/Receipts/GridRepublic.pkg"
    sprintf(s, "rm -rf %s", receiptNameEscaped[brandID]);
    system (s);

    // err_fsref = FSPathMakeRef((StringPtr)"/Applications/GridRepublic Desktop.app", &fileRef, NULL);
    err_fsref = FSPathMakeRef((StringPtr)appName[brandID], &fileRef, NULL);

    if (finalInstallAction == launchWhenDone) {
        // If system is set up to run BOINC Client as a daemon using launchd, launch it 
        //  as a daemon and allow time for client to start before launching BOINC Manager.
        err = stat("/Library/LaunchDaemons/edu.berkeley.boinc.plist", &sbuf);
        if (err == noErr) {
            system("launchctl unload /Library/LaunchDaemons/edu.berkeley.boinc.plist");
            i = system("launchctl load /Library/LaunchDaemons/edu.berkeley.boinc.plist");
            if (i == 0) sleep (2);
        }
        err = LSOpenFSRef(&fileRef, NULL);
    }

    return 0;
}
Example #2
0
Boolean myFilterProc(DialogRef theDialog, EventRecord *theEvent, DialogItemIndex *itemHit) {
    static time_t       lastCheckTime = 0;
    time_t              now = time(NULL);
    pid_t               waitPermissionsPID = 0;

    if (now != lastCheckTime) {
            waitPermissionsPID = FindProcessPID("WaitPermissions", 0);
            if (waitPermissionsPID == 0) {
                *itemHit = kStdOkItemIndex;
                return true;
            }
        lastCheckTime = now;
        // Limit delay to 3 minutes
        if ((now - waitPermissionsStartTime) > 180) {
            *itemHit = kStdOkItemIndex;
            return true;
        }
    }

return false;
}
Example #3
0
void CScreensaver::HandleRPCError() {
    static time_t last_RPC_retry = 0;
    time_t now = time(0);
   
    // Attempt to restart BOINC Client if needed, reinitialize the RPC client and state
    rpc->close();
    m_bConnected = false;
    
    if (saverState == SaverState_CantLaunchCoreClient) {
        if ((now - last_RPC_retry) < RPC_RETRY_INTERVAL) {
            return;
        }
        last_RPC_retry = now;
    } else {
        // There is a possible race condition where the Core Client was in the  
        // process of shutting down just as ScreenSaver started, so initBOINCApp() 
        // found it already running but now it has shut down.  This code takes 
        // care of that and other situations where the Core Client quits unexpectedy.  
        // Code in initBOINC_App() limits # launch retries to 3 to prevent thrashing.
        if (FindProcessPID("boinc", 0) == 0) {
            saverState = SaverState_RelaunchCoreClient;
            m_bResetCoreState = true;
         }
    }
    
    // If Core Client is hung, it might cause RPCs to hang, preventing us from 
    // shutting down the Data Management Thread, so don't reinitialize the RPC 
    // client if we have told the Data Management Thread to exit.
    if (m_bQuitDataManagementProc) {
        return;
    }
    
    // Otherwise just reinitialize the RPC client and state and keep trying
    if (!rpc->init(NULL)) {
        m_bConnected = true;
    }
    // Error message after timeout?
}
Example #4
0
int main(int argc, char *argv[])
{
    Boolean                 Success;
    ProcessSerialNumber     ourProcess, installerPSN;
    short                   itemHit;
    long                    brandID = 0;
    int                     i;
    pid_t                   installerPID = 0, coreClientPID = 0, waitPermissionsPID = 0;
    FSRef                   fileRef;
    OSStatus                err, err_fsref;
    FILE                    *f;
    char                    s[256];
    char                    *q;
#ifdef SANDBOX
    uid_t                   saved_euid, saved_uid, b_m_uid;
    passwd                  *pw;
    int                     finalInstallAction;
    DialogRef               theWin;

#else   // SANDBOX
    group                   *grp;
#endif  // SANDBOX

    appName[0] = "/Applications/BOINCManager.app";
    appNameEscaped[0] = "/Applications/BOINCManager.app";
    brandName[0] = "BOINC";
    saverName[0] = "BOINCSaver";
    saverNameEscaped[0] = "BOINCSaver";
    receiptNameEscaped[0] = "/Library/Receipts/BOINC.pkg";

    appName[1] = "/Applications/GridRepublic Desktop.app";
    appNameEscaped[1] = "/Applications/GridRepublic\\ Desktop.app";
    brandName[1] = "GridRepublic";
    saverName[1] = "GridRepublic";
    saverNameEscaped[1] = "GridRepublic";
    receiptNameEscaped[1] = "/Library/Receipts/GridRepublic.pkg";

    appName[2] = "/Applications/Progress Thru Processors Desktop.app";
    appNameEscaped[2] = "/Applications/Progress\\ Thru\\ Processors\\ Desktop.app";
    brandName[2] = "Progress Thru Processors";
    saverName[2] = "Progress Thru Processors";
    saverNameEscaped[2] = "Progress\\ Thru\\ Processors";
    receiptNameEscaped[2] = "/Library/Receipts/Progress\\ Thru\\ Processors.pkg";

    ::GetCurrentProcess (&ourProcess);
    
    // getlogin() gives unreliable results under OS 10.6.2, so use environment
    strncpy(loginName, getenv("USER"), sizeof(loginName)-1);

    err = Gestalt(gestaltSystemVersion, &OSVersion);
    if (err != noErr)
        return err;

    for (i=0; i<argc; i++) {
        if (strcmp(argv[i], "-part2") == 0)
            return DeleteReceipt();
    }

    Initialize();

    QuitBOINCManager('BNC!'); // Quit any old instance of BOINC manager
    sleep(2);

    // Core Client may still be running if it was started without Manager
    coreClientPID = FindProcessPID("boinc", 0);
    if (coreClientPID)
        kill(coreClientPID, SIGTERM);   // boinc catches SIGTERM & exits gracefully

    err = FindProcess ('APPL', 'xins', &installerPSN);
    if (err == noErr)
        err = GetProcessPID(&installerPSN , &installerPID);

    brandID = GetBrandID();
    
    if ((brandID < 0) || (brandID >= NUMBRANDS)) {       // Safety check
        brandID = 0;
    }
    
    if (OSVersion < 0x1040) {
        ::SetFrontProcess(&ourProcess);
        // Remove everything we've installed
        // "\pSorry, this version of GridRepublic requires system 10.4.0 or higher."
        s[0] = sprintf(s+1, "Sorry, this version of %s requires system 10.4.0 or higher.", brandName[brandID]);
        StandardAlert (kAlertStopAlert, (StringPtr)s, NULL, NULL, &itemHit);

        // "rm -rf /Applications/GridRepublic\\ Desktop.app"
        sprintf(s, "rm -rf %s", appNameEscaped[brandID]);
        system (s);
        
        // "rm -rf /Library/Screen\\ Savers/GridRepublic.saver"
        sprintf(s, "rm -rf /Library/Screen\\ Savers/%s.saver", saverNameEscaped[brandID]);
        system (s);
        
        // "rm -rf /Library/Receipts/GridRepublic.pkg"
        sprintf(s, "rm -rf %s", receiptNameEscaped[brandID]);
        system (s);

        // We don't customize BOINC Data directory name for branding
        system ("rm -rf /Library/Application\\ Support/BOINC\\ Data");

        err = kill(installerPID, SIGKILL);

	ExitToShell();
    }
    
    sleep (2);

    // Install all_projects_list.xml file, but only if one doesn't 
    // already exist, since a pre-existing one is probably newer.
    f = fopen("/Library/Application Support/BOINC Data/all_projects_list.xml", "r");
    if (f) {
        fclose(f);      // Already exists
    } else {
        system ("cp -fp Contents/Resources/all_projects_list.xml /Library/Application\\ Support/BOINC\\ Data/");
        system ("chmod a-x /Library/Application\\ Support/BOINC\\ Data/all_projects_list.xml");
    }
    
    Success = false;
    
#ifdef SANDBOX

    CheckUserAndGroupConflicts();

    for (i=0; i<5; ++i) {
        err = CreateBOINCUsersAndGroups();
        if (err != noErr) {
//          print_to_log_file("CreateBOINCUsersAndGroups returned %d (repetition=%d)", err, i);
            continue;
        }
        
        // err = SetBOINCAppOwnersGroupsAndPermissions("/Applications/GridRepublic Desktop.app");
        err = SetBOINCAppOwnersGroupsAndPermissions(appName[brandID]);
        
        if (err != noErr) {
//          print_to_log_file("SetBOINCAppOwnersGroupsAndPermissions returned %d (repetition=%d)", err, i);
            continue;
        }

        err = SetBOINCDataOwnersGroupsAndPermissions();
        if (err != noErr) {
//          print_to_log_file("SetBOINCDataOwnersGroupsAndPermissions returned %d (repetition=%d)", err, i);
            continue;
        }
        
        err = check_security(appName[brandID], "/Library/Application Support/BOINC Data", true, false);
        if (err == noErr)
            break;
//          print_to_log_file("check_security returned %d (repetition=%d)", err, i);
    }
    
#else   // ! defined(SANDBOX)

    // The BOINC Manager and Core Client have the set-user-ID-on-execution 
    // flag set, so their ownership is important and must match the 
    // ownership of the BOINC Data directory.
    
    // Find an appropriate admin user to set as owner of installed files
    // First, try the user currently logged in
    grp = getgrnam("admin");
    i = 0;
    while ((p = grp->gr_mem[i]) != NULL) {   // Step through all users in group admin
        if (strcmp(p, loginName) == 0) {
            Success = true;     // Logged in user is a member of group admin
            break;
        }
        ++i;
    }
    
    // If currently logged in user is not admin, use first non-root admin user
    if (!Success) {
        i = 0;
        while ((p = grp->gr_mem[i]) != NULL) {   // Step through all users in group admin
            if (strcmp(p, "root") != 0)
                break;
            ++i;
        }
    }

    // Set owner of branded BOINCManager and contents, including core client
    // "chown -Rf username /Applications/GridRepublic\\ Desktop.app"
    sprintf(s, "chown -Rf %s %s", p, appNameEscaped[brandID]);
    system (s);

    // Set owner of BOINC Screen Saver
    // "chown -Rf username /Library/Screen\\ Savers/GridRepublic.saver"
    sprintf(s, "chown -Rf %s /Library/Screen\\ Savers/%s.saver", p, saverNameEscaped[brandID]);
    system (s);

    //  We don't customize BOINC Data directory name for branding
    // "chown -Rf username /Library/Application\\ Support/BOINC\\ Data"
    sprintf(s, "chown -Rf %s /Library/Application\\ Support/BOINC\\ Data", p);
    system (s);

    // "chmod -R a+s /Applications/GridRepublic\\ Desktop.app"
    sprintf(s, "chmod -R a+s %s", appNameEscaped[brandID]);
    system (s);

#endif   // ! defined(SANDBOX)

    // Remove any branded versions of BOINC other than ours (i.e., old versions) 
    for (i=0; i< NUMBRANDS; i++) {
        if (i == brandID) continue;
        
        // "rm -rf /Applications/GridRepublic\\ Desktop.app"
        sprintf(s, "rm -rf %s", appNameEscaped[i]);
        system (s);
        
        // "rm -rf /Library/Screen\\ Savers/GridRepublic.saver"
        sprintf(s, "rm -rf /Library/Screen\\ Savers/%s.saver", saverNameEscaped[i]);
        system (s);
    }
    
   if (brandID == 0) {  // Installing generic BOINC
        system ("rm -f /Library/Application\\ Support/BOINC\\ Data/Branding");
    }
    
    // err_fsref = FSPathMakeRef((StringPtr)"/Applications/GridRepublic Desktop.app", &fileRef, NULL);
    err_fsref = FSPathMakeRef((StringPtr)appName[brandID], &fileRef, NULL);
    
    if (err_fsref == noErr)
        err = LSRegisterFSRef(&fileRef, true);
    
    err = UpdateAllVisibleUsers(brandID);
    if (err != noErr)
        return err;
 
#ifdef SANDBOX
    err = CheckLogoutRequirement(&finalInstallAction);
    
    if (finalInstallAction == launchWhenDone) {
        // Wait for BOINC's RPC socket address to become available to user boinc_master, in
        // case we are upgrading from a version which did not run as user boinc_master.
        saved_uid = getuid();
        saved_euid = geteuid();
        
        pw = getpwnam("boinc_master");
        b_m_uid = pw->pw_uid;
        seteuid(b_m_uid);
        
        for (i=0; i<120; i++) {
            err = TestRPCBind();
            if (err == noErr)
                break;
            
            sleep(1);
        }
        
        seteuid(saved_euid);

        ProcessSerialNumber ourPSN;
        ProcessInfoRec      pInfo;
        FSRef               ourFSRef, theFSRef;
        char                thePath[MAXPATHLEN];
        
        // Get the full path to this PostInstall application's bundle
        err = GetCurrentProcess (&ourPSN);
        if (err)
            return -1000;          // Should never happen
        
        memset(&pInfo, 0, sizeof(pInfo));
        pInfo.processInfoLength = sizeof( ProcessInfoRec );
        err = GetProcessInformation(&ourPSN, &pInfo);
        if (err)
            return -1001;          // Should never happen
        
        err = GetProcessBundleLocation(&ourPSN, &ourFSRef);
        if (err)
            return -1002;          // Should never happen

        err = FSRefMakePath (&ourFSRef, (UInt8*)thePath, sizeof(thePath));
        if (err)
            return -1003;          // Should never happen
        
        q = strrchr(thePath, '/');
        if (q == NULL)
            return -1004;          // Should never happen

        *++q = '\0';
        strlcat(thePath, "WaitPermissions.app", sizeof(thePath));
        err = FSPathMakeRef((StringPtr)thePath, &theFSRef, NULL);
        
        // When we first create the boinc_master group and add the current user to the 
        // new group, there is a delay before the new group membership is recognized.  
        // If we launch the BOINC Manager too soon, it will fail with a -1037 permissions 
        // error, so we wait until the current user can access the switcher application.
        // Apparently, in order to get the changed permissions / group membership, we must 
        // launch a new process belonging to the user.  It may also need to be in a new 
        // process group or new session. Neither system() nor popen() works, even after 
        // setting the uid and euid back to the logged in user, but LSOpenFSRef() does.
        // The WaitPermissions application loops until it can access the switcher 
        // application.
        err = LSOpenFSRef(&theFSRef, NULL);

        waitPermissionsStartTime = time(NULL);
        for (i=0; i<15; i++) {     // Show "Please wait..." alert after 15 seconds
            waitPermissionsPID = FindProcessPID("WaitPermissions", 0);
            if (waitPermissionsPID == 0) {
                return 0;
            }
            sleep(1);
        }
        
        CreateStandardAlert(kAlertNoteAlert, CFSTR("Finishing install.  Please wait ..."), CFSTR("This may take a few more minutes."), NULL, &theWin);
        HideDialogItem(theWin, kStdOkItemIndex);
        RemoveDialogItems(theWin, kStdOkItemIndex, 1, false);
        RunStandardAlert(theWin, &myFilterProc, &itemHit);

    }
#endif   // SANDBOX
    
    return 0;
}
Example #5
0
// Returns new desired Animation Frequency (per second) or 0 for no change
int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) {
    int newFrequency = TEXTLOGOFREQUENCY;
    *coveredFreq = 0;
    pid_t myPid;
    CC_STATE ccstate;
    OSStatus err;
    
    if (ScreenIsBlanked) {
        setSSMessageText(0);   // No text message
        *theMessage = m_MessageText;
        return NOTEXTLOGOFREQUENCY;
    }
    
    CheckDualGPUStatus();
    
    switch (saverState) {
    case SaverState_RelaunchCoreClient:
        err = initBOINCApp();
        break;
    
    case  SaverState_LaunchingCoreClient:
        if (m_wasAlreadyRunning) {
            setSSMessageText(ConnectingCCMsg);
        } else {
            setSSMessageText(LaunchingCCMsg);
        }
            
        myPid = FindProcessPID(NULL, m_CoreClientPID);
        if (myPid) {
            saverState = SaverState_CoreClientRunning;
            if (!rpc->init(NULL)) {     // Initialize communications with Core Client
                m_bConnected = true;
                if (IsDualGPUMacbook) {
                    ccstate.clear();
                    ccstate.global_prefs.init_bools();
                    int result = rpc->get_state(ccstate);
                    if (!result) {
                        OKToRunOnBatteries = ccstate.global_prefs.run_on_batteries;
                    } else {
                        OKToRunOnBatteries = false;
                    }
                    
                    if (OKToRunOnBatteries) {
                        SetDiscreteGPU(true);
                    }
                }
            }

            // Set up a separate thread for communicating with Core Client
            // and running screensaver graphics
            CreateDataManagementThread();
            // ToDo: Add a timeout after which we display error message
        } else
            // Take care of the possible race condition where the Core Client was in the  
            // process of shutting down just as ScreenSaver started, so initBOINCApp() 
            // found it already running but now it has shut down.
            if (m_wasAlreadyRunning) { // If we launched it, then just wait for it to start
                saverState = SaverState_RelaunchCoreClient;
            }
         break;

    case SaverState_CoreClientRunning:
        if (IsDualGPUMacbook && RunningOnBattery && !OKToRunOnBatteries) {
            setSSMessageText(RunningOnBatteryMsg);
            break;
        }
            
        // RPC called in DataManagementProc()
        setSSMessageText(ConnectingCCMsg);
        
        if (! m_bResetCoreState) {
            saverState = SaverState_ConnectedToCoreClient;
        }
    break;
    
    case SaverState_ConnectedToCoreClient:
        if (IsDualGPUMacbook && RunningOnBattery && !OKToRunOnBatteries) {
            setSSMessageText(RunningOnBatteryMsg);
            break;
        }

        switch (m_hrError) {
        case 0:
            setSSMessageText(ConnectedCCMsg);
            break;  // No status response yet from DataManagementProc
        case SCRAPPERR_SCREENSAVERBLANKED:
            setSSMessageText(0);   // No text message
            ScreenIsBlanked = true;
            if (IsDualGPUMacbook && (GPUSelectConnect != IO_OBJECT_NULL)) {
                IOServiceClose(GPUSelectConnect);
                GPUSelectConnect = IO_OBJECT_NULL;
            }
            break;
#if 0   // Not currently used
        case SCRAPPERR_QUITSCREENSAVERREQUESTED:
//            setSSMessageText(BOINCExitedSaverMode);
            // Wait 1 second to allow ScreenSaver engine to close us down
            if (++gQuitCounter > (m_MessageText[0] ? TEXTLOGOFREQUENCY : NOTEXTLOGOFREQUENCY)) {
                closeBOINCSaver();
                KillScreenSaver(); // Stop the ScreenSaver Engine
            }
            break;
#endif
        case SCRAPPERR_CANTLAUNCHDEFAULTGFXAPP:
            setSSMessageText(CantLaunchDefaultGFXAppMsg);
            break;
        case SCRAPPERR_DEFAULTGFXAPPCANTCONNECT:
            setSSMessageText(DefaultGFXAppCantRPCMsg);
            break;
         case SCRAPPERR_DEFAULTGFXAPPCRASHED:
            setSSMessageText(DefaultGFXAppCrashedMsg);
            break;
        default:
            // m_bErrorMode is TRUE if we should display moving logo (no graphics app is running)
            // m_bErrorMode is FALSE if a graphics app was launched and has not exit
            if (! m_bErrorMode) { 
                // NOTE: My tests seem to confirm that the top window is always the first 
                // window returned by NSWindowList under OS 10.5 and the second window 
                // returned by NSWindowList under OS 10.3.9 and OS 10.4.  However, Apple's 
                // documentation is unclear whether we can depend on this.  So I have 
                // added some safety by doing two things:
                // [1] Only use the NSWindowList test when we have started project or default 
                //      graphics.
                // [2] Assume that our window is covered 45 seconds after starting project 
                //     graphics even if the NSWindowList test did not indicate that is so.
                //
                // The -animateOneFrame method in Mac_SaverModuleView.m does the NSWindowList test 
                // only if we return a non-zero value for coveredFreq.
                //
                // Tell the calling routine to set the frame rate to NOTEXTLOGOFREQUENCY if 
                // NSWindowList indicates that science app graphics window has covered our window.
                *coveredFreq = NOTEXTLOGOFREQUENCY;
                
                if (m_iGraphicsStartingMsgCounter > 0) {
                    // Show ScreenSaverAppStartingMsg for GFX_STARTING_MSG_DURATION seconds or until 
                    // NSWindowList indicates that science app graphics window has covered our window
                    setSSMessageText(ScreenSaverAppStartingMsg);
                    m_iGraphicsStartingMsgCounter--;
                } else {
                    // Don't waste CPU cycles when the science app is drawing over our window
                    setSSMessageText(0);   // No text message
                }
            }           // End if (! m_bErrorMode)
            break;      // End default case of switch (m_hrError)
            
        }       // end switch (m_hrError)
        break;  // End case SaverState_ConnectedToCoreClient of switch (saverState)

    case SaverState_ControlPanelTestMode:
        setSSMessageText(BOINCTestModeMsg);
        break;

    case SaverState_UnrecoverableError:
        setSSMessageText(BOINCUnrecoverableErrorMsg);
        break;

    case SaverState_CantLaunchCoreClient:
        if (IsDualGPUMacbook && RunningOnBattery && !OKToRunOnBatteries) {
            setSSMessageText(RunningOnBatteryMsg);
            break;
        }
        
        setSSMessageText(CantLaunchCCMsg);
        
        // Set up a separate thread for running screensaver graphics 
        // even if we can't communicate with core client
        CreateDataManagementThread();
        break;

    case SaverState_Idle:
        break;      // Should never get here; fixes compiler warning
    }           // end switch (saverState)

    if (IsDualGPUMacbook && RunningOnBattery && !OKToRunOnBatteries) {
        if ((m_dwBlankScreen) && (time(0) > m_dwBlankTime) && (m_dwBlankTime > 0)) {
            setSSMessageText(0);   // No text message
            ScreenIsBlanked = true;
        }
    }
    
    if (m_MessageText[0]) {
        newFrequency = TEXTLOGOFREQUENCY;
    } else {
        newFrequency = NOTEXTLOGOFREQUENCY;
    }
    
    *theMessage = m_MessageText;
    return newFrequency;
}
Example #6
0
OSStatus CScreensaver::initBOINCApp() {
    char boincPath[2048];
    pid_t myPid;
    int status;
    OSStatus err;
    long brandId = 0;

    saverState = SaverState_CantLaunchCoreClient;
    
    brandId = GetBrandID();
    switch(brandId) {
    case 1:
        m_BrandText = "GridRepublic Desktop";
         break;
    case 2:
        m_BrandText = "Progress Thru Processors Desktop";
         break;
    case 3:
        m_BrandText = "Charity Engine Desktop";
         break;
    default:
        m_BrandText = "BOINC";
        break;
    }

    m_CoreClientPID = FindProcessPID("boinc", 0);
    if (m_CoreClientPID) {
        m_wasAlreadyRunning = true;
        saverState = SaverState_LaunchingCoreClient;
        retryCount = 0;
        return noErr;
    }
    
    m_wasAlreadyRunning = false;
    
    if (++retryCount > 3)   // Limit to 3 relaunches to prevent thrashing
        return -1;

    // Find boinc client within BOINCManager.app
    // First, try default path
    strcpy(boincPath, "/Applications/");
    if (brandId) {
        strcat(boincPath, m_BrandText);
    } else {
        strcat(boincPath, "BOINCManager");
    }
    strcat(boincPath, ".app/Contents/Resources/boinc");

    // If not at default path, search for it by creator code and bundle identifier
    if (!boinc_file_exists(boincPath)) {
        err = GetpathToBOINCManagerApp(boincPath, sizeof(boincPath));
        if (err) {
            saverState = SaverState_CantLaunchCoreClient;
            return err;
        } else {
            strcat(boincPath, "/Contents/Resources/boinc");
        }
    }

    if ( (myPid = fork()) < 0)
        return -1;
    else if (myPid == 0)			// child
    {
      // We don't customize BOINC Data directory name for branding
#if 0   // Code for separate data in each user's private directory
        char buf[256];
        safe_strcpy(buf, getenv("HOME"));
        safe_strcat(buf, "/Library/Application Support/BOINC Data");
        status = chdir(buf);
#else   // All users share the same data
        status = chdir("/Library/Application Support/BOINC Data");
#endif
        if (status) {
            perror("chdir");
            fflush(NULL);
            _exit(status);
        }

        status = execl(boincPath, boincPath, "-redirectio", "-saver", (char *) 0);
        fflush(NULL);
        _exit(127);         // execl error (execl should never return)
    } else {
        m_CoreClientPID = myPid;		// make this available globally
        saverState = SaverState_LaunchingCoreClient;
    }

    return noErr;
}
Example #7
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);
}