diff --git a/clientgui/mac/SetVersion.cpp b/clientgui/mac/SetVersion.cpp
index 215359ffea..9ad6d6e6b8 100644
--- a/clientgui/mac/SetVersion.cpp
+++ b/clientgui/mac/SetVersion.cpp
@@ -40,6 +40,7 @@ int file_exists(const char* path);
int FixInfoPlistFile(char* name);
int FixInfoPlist_Strings(char* myPath, char* name);
int MakeBOINCPackageInfoPlistFile(char* myPath, char* brand);
+int MakeBOINCRestartPackageInfoPlistFile(char* myPath, char* brand);
int MakeMetaPackageInfoPlistFile(char* myPath, char* brand);
int main(int argc, char** argv) {
@@ -91,6 +92,9 @@ int main(int argc, char** argv) {
err = MakeBOINCPackageInfoPlistFile("./Pkg-Info.plist", "BOINC Manager");
if (err) retval = err;
+ err = MakeBOINCRestartPackageInfoPlistFile("./Pkg_Restart-Info.plist", "BOINC Manager");
+ if (err) retval = err;
+
err = MakeMetaPackageInfoPlistFile("./Mpkg-Info.plist", "BOINC Manager");
return retval;
}
@@ -284,7 +288,7 @@ int MakeBOINCPackageInfoPlistFile(char* myPath, char* brand) {
retval = fclose(f);
}
else {
- puts("Error creating file Pkg-Info.plist\n");
+ printf("Error creating file %s\n", myPath);
retval = -1;
}
@@ -292,6 +296,58 @@ int MakeBOINCPackageInfoPlistFile(char* myPath, char* brand) {
}
+// Create a MetaPackage whcih runs only BOINC,pkg but specifies Restart Required
+int MakeBOINCRestartPackageInfoPlistFile(char* myPath, char* brand) {
+ int retval = 0;
+ FILE *f;
+
+ if (IsFileCurrent(myPath))
+ return 0;
+
+ f = fopen(myPath, "w");
+ if (f)
+ {
+ fprintf(f, "\n");
+ fprintf(f, "\n");
+ fprintf(f, "\n\n");
+ fprintf(f, "\tCFBundleGetInfoString\n");
+ fprintf(f, "\t%s %s\n", brand, BOINC_VERSION_STRING);
+ fprintf(f, "\tCFBundleIdentifier\n\tedu.berkeley.boinc_r\n");
+ fprintf(f, "\tCFBundleShortVersionString\n");
+ fprintf(f, "\t%s\n", BOINC_VERSION_STRING);
+ fprintf(f, "\tIFMajorVersion\n\t%d\n", BOINC_MAJOR_VERSION);
+ fprintf(f, "\tIFMinorVersion\n\t%d\n", BOINC_MINOR_VERSION);
+ fprintf(f, "\tIFPkgFlagAllowBackRev\n\t1\n");
+ fprintf(f, "\tIFPkgFlagAuthorizationAction\n\tAdminAuthorization\n");
+ fprintf(f, "\tIFPkgFlagRestartAction\n\tRequiredRestart\n");
+ fprintf(f, "\tIFPkgFlagRootVolumeOnly\n\t1\n");
+ fprintf(f, "\tIFPkgFlagComponentDirectory\n\t../\n");
+
+ fprintf(f, "\tIFPkgFlagPackageList\n");
+
+ fprintf(f, "\t\n");
+ fprintf(f, "\t\t\n");
+ fprintf(f, "\t\t\tIFPkgFlagPackageLocation\n\t\t\tBOINC.pkg\n");
+ fprintf(f, "\t\t\tIFPkgFlagPackageSelection\n\t\t\trequired\n");
+ fprintf(f, "\t\t\n");
+ fprintf(f, "\t\n");
+
+ fprintf(f, "\tIFPkgFormatVersion\n\t0.10000000149011612\n");
+ fprintf(f, "\n\n");
+
+ fflush(f);
+ retval = fclose(f);
+ }
+ else {
+ printf("Error creating file %s\n", myPath);
+ retval = -1;
+ }
+
+ return retval;
+}
+
+
+// Make a MetaPackage to install both BOINC and VirtualBox
int MakeMetaPackageInfoPlistFile(char* myPath, char* brand) {
int retval = 0;
FILE *f;
@@ -313,7 +369,9 @@ int MakeMetaPackageInfoPlistFile(char* myPath, char* brand) {
fprintf(f, "\tIFMajorVersion\n\t%d\n", BOINC_MAJOR_VERSION);
fprintf(f, "\tIFMinorVersion\n\t%d\n", BOINC_MINOR_VERSION);
fprintf(f, "\tIFPkgFlagAllowBackRev\n\t1\n");
- fprintf(f, "\tIFPkgFlagAuthorizationAction\n\tRootAuthorization\n");
+ fprintf(f, "\tIFPkgFlagAuthorizationAction\n\tAdminAuthorization\n");
+ fprintf(f, "\tIFPkgFlagRestartAction\n\tNoRestart\n");
+ fprintf(f, "\tIFPkgFlagRootVolumeOnly\n\t1\n");
fprintf(f, "\tIFPkgFlagComponentDirectory\n\t../\n");
fprintf(f, "\tIFPkgFlagPackageList\n");
@@ -337,7 +395,7 @@ int MakeMetaPackageInfoPlistFile(char* myPath, char* brand) {
retval = fclose(f);
}
else {
- puts("Error creating file Mpkg-Info.plist\n");
+ printf("Error creating file %s\n", myPath);
retval = -1;
}
diff --git a/mac_installer/Installer.cpp b/mac_installer/Installer.cpp
index 6b79cb982b..d8770cc279 100644
--- a/mac_installer/Installer.cpp
+++ b/mac_installer/Installer.cpp
@@ -40,7 +40,7 @@
void Initialize(void); /* function prototypes */
Boolean IsUserMemberOfGroup(const char *userName, const char *groupName);
-OSStatus GetFinalAction(CFStringRef *restartValue);
+Boolean IsRestartNeeded();
OSErr FindProcess (OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN);
static OSErr QuitAppleEventHandler(const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon);
void print_to_log_file(const char *format, ...);
@@ -52,14 +52,17 @@ void strip_cr(char *buf);
Boolean gQuitFlag = false; /* global */
+#if 0
CFStringRef valueRestartRequired = CFSTR("RequiredRestart");
CFStringRef valueLogoutRequired = CFSTR("RequiredLogout");
CFStringRef valueNoRestart = CFSTR("NoRestart");
-
+#endif
int main(int argc, char *argv[])
{
- char pkgPath[MAXPATHLEN], infoPlistPath[MAXPATHLEN], MetaPkgPath[MAXPATHLEN];
+ char pkgPath[MAXPATHLEN], pkgRestartPath[MAXPATHLEN];
+ char infoPlistPath[MAXPATHLEN];
+ char MetaPkgPath[MAXPATHLEN], MetaPkgRestartPath[MAXPATHLEN];
char brand[64], s[256];
char *p;
ProcessSerialNumber ourPSN, installerPSN;
@@ -67,17 +70,10 @@ int main(int argc, char *argv[])
long response;
short itemHit;
pid_t installerPID = 0;
- FSRef infoPlistFileRef;
- Boolean isDirectory, result;
- CFURLRef xmlURL = NULL;
- CFDataRef xmlDataIn = NULL;
- CFDataRef xmlDataOut = NULL;
- CFPropertyListRef propertyListRef = NULL;
- CFStringRef restartKey = CFSTR("IFPkgFlagRestartAction");
- CFStringRef currentValue = NULL, desiredValue = NULL;
- CFStringRef errorString = NULL;
OSStatus err = noErr;
struct stat stat_buf;
+ Boolean restartNeeded = true;
+ FILE *restartNeededFile;
Initialize();
@@ -109,6 +105,13 @@ int main(int argc, char *argv[])
strlcpy(MetaPkgPath, pkgPath, sizeof(MetaPkgPath));
strlcat(MetaPkgPath, "+VirtualBox.mpkg", sizeof(MetaPkgPath));
+
+ strlcpy(MetaPkgRestartPath, pkgPath, sizeof(MetaPkgRestartPath));
+ strlcat(MetaPkgRestartPath, "+VirtualBox .mpkg", sizeof(MetaPkgRestartPath));
+
+ strlcpy(pkgRestartPath, pkgPath, sizeof(MetaPkgPath));
+ strlcat(pkgRestartPath, ".mpkg", sizeof(pkgPath));
+
strlcat(pkgPath, ".pkg", sizeof(pkgPath));
err = Gestalt(gestaltSystemVersion, &response);
if (err != noErr)
@@ -132,78 +135,29 @@ int main(int argc, char *argv[])
}
// 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);
system (s);
+ restartNeeded = IsRestartNeeded();
+
+ // Write a temp file to tell our PostInstall.app whether restart is needed
+ restartNeededFile = fopen("/tmp/BOINC_restart_flag", "w");
+ if (restartNeededFile) {
+ fputs(restartNeeded ? "1\n" : "0\n", restartNeededFile);
+ fclose(restartNeededFile);
+ }
+
err = Gestalt(gestaltSystemVersion, &response);
if (err != noErr)
return err;
- err = GetFinalAction(&desiredValue);
-
- strlcpy(infoPlistPath, pkgPath, sizeof(infoPlistPath));
- strlcat(infoPlistPath, "/Contents/Info.plist", sizeof(infoPlistPath));
-
- err = FSPathMakeRef((UInt8*)infoPlistPath, &infoPlistFileRef, &isDirectory);
- if (err)
- return err;
-
- xmlURL = CFURLCreateFromFSRef(NULL, &infoPlistFileRef);
- if (xmlURL == NULL)
- return -1;
-
- // Read XML Data from file
- result = CFURLCreateDataAndPropertiesFromResource(NULL, xmlURL, &xmlDataIn, NULL, NULL, &err);
- if (err == noErr)
- if (!result)
- err = coreFoundationUnknownErr;
-
- if (err == noErr) { // Convert XML Data to internal CFPropertyListRef / CFDictionaryRef format
- propertyListRef = CFPropertyListCreateFromXMLData(NULL, xmlDataIn, kCFPropertyListMutableContainersAndLeaves, &errorString);
- if (propertyListRef == NULL)
- err = coreFoundationUnknownErr;
- }
-
- if (err == noErr) { // Get current value for our key
- currentValue = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)propertyListRef, restartKey);
- if (currentValue == NULL)
- err = coreFoundationUnknownErr;
- }
-
- if (err == noErr) {
- if (CFStringCompare(currentValue, desiredValue, 0) != kCFCompareEqualTo) { // If current value != desired value
- // Replace value for key with desired value
- CFDictionaryReplaceValue((CFMutableDictionaryRef)propertyListRef, restartKey, desiredValue);
-
- // Convert internal CFPropertyListRef / CFDictionaryRef format to XML data
- xmlDataOut = CFPropertyListCreateXMLData(NULL, propertyListRef);
- if (xmlDataOut == NULL)
- err = coreFoundationUnknownErr;
-
- if (err == noErr) { // Write revised XML Data back to the file
- result = CFURLWriteDataAndPropertiesToResource (xmlURL, xmlDataOut, NULL, &err);
- if (err == noErr)
- if (!result)
- err = coreFoundationUnknownErr;
- }
- }
- }
-
- if (xmlURL)
- CFRelease(xmlURL);
- if (xmlDataIn)
- CFRelease(xmlDataIn);
- if (xmlDataOut)
- CFRelease(xmlDataOut);
- if (propertyListRef)
- CFRelease(propertyListRef);
-
if (err == noErr) {
if ((response < 0x1050) || stat(MetaPkgPath, &stat_buf)) { // stat() returns zero on success
- sprintf(infoPlistPath, "open \"%s\" &", pkgPath);
+ sprintf(infoPlistPath, "open \"%s\" &", restartNeeded ? pkgRestartPath : pkgPath);
} else {
- sprintf(infoPlistPath, "open \"%s\" &", MetaPkgPath);
+ sprintf(infoPlistPath, "open \"%s\" &", restartNeeded ? MetaPkgRestartPath : MetaPkgPath);
}
system(infoPlistPath);
}
@@ -234,7 +188,7 @@ Boolean IsUserMemberOfGroup(const char *userName, const char *groupName) {
}
-OSStatus GetFinalAction(CFStringRef *restartValue)
+Boolean IsRestartNeeded()
{
passwd *pw = NULL;
group *grp = NULL;
@@ -244,61 +198,58 @@ OSStatus GetFinalAction(CFStringRef *restartValue)
long response;
char loginName[256];
- *restartValue = valueRestartRequired;
-
grp = getgrnam(boinc_master_group_name);
if (grp == NULL)
- return noErr; // Group boinc_master does not exist
+ return true; // Group boinc_master does not exist
boinc_master_gid = grp->gr_gid;
grp = getgrnam(boinc_project_group_name);
if (grp == NULL)
- return noErr; // Group boinc_project does not exist
+ return true; // Group boinc_project does not exist
boinc_project_gid = grp->gr_gid;
pw = getpwnam(boinc_master_user_name);
if (pw == NULL)
- return noErr; // User boinc_master does not exist
+ return true; // User boinc_master does not exist
boinc_master_uid = pw->pw_uid;
if (pw->pw_gid != boinc_master_gid)
- return noErr; // User boinc_master does not have group boinc_master as its primary group
+ return true; // User boinc_master does not have group boinc_master as its primary group
pw = getpwnam(boinc_project_user_name);
if (pw == NULL)
- return noErr; // User boinc_project does not exist
+ return true; // User boinc_project does not exist
boinc_project_uid = pw->pw_uid;
if (pw->pw_gid != boinc_project_gid)
- return noErr; // User boinc_project does not have group boinc_project as its primary group
+ return true; // User boinc_project does not have group boinc_project as its primary group
err = Gestalt(gestaltSystemVersion, &response);
if ((err == noErr) && (response >= 0x1050)) {
if (boinc_master_gid < 501)
- return noErr; // We will change boinc_master_gid to a value > 501
+ return true; // We will change boinc_master_gid to a value > 501
if (boinc_project_gid < 501)
- return noErr; // We will change boinc_project_gid to a value > 501
+ return true; // We will change boinc_project_gid to a value > 501
if (boinc_master_uid < 501)
- return noErr; // We will change boinc_master_uid to a value > 501
+ return true; // We will change boinc_master_uid to a value > 501
if (boinc_project_uid < 501)
- return noErr; // We will change boinc_project_uid to a value > 501
+ return true; // We will change boinc_project_uid to a value > 501
}
#ifdef SANDBOX
strncpy(loginName, getenv("USER"), sizeof(loginName)-1);
if (loginName[0]) {
if (IsUserMemberOfGroup(loginName, boinc_master_group_name)) {
- *restartValue = valueNoRestart;
- return noErr; // Logged in user is already a member of group boinc_master
+ return false; // Logged in user is already a member of group boinc_master
}
}
#endif // SANDBOX
- return noErr;
+ return true;
}
diff --git a/mac_installer/PostInstall.cpp b/mac_installer/PostInstall.cpp
index 4718e06909..0aaadee127 100644
--- a/mac_installer/PostInstall.cpp
+++ b/mac_installer/PostInstall.cpp
@@ -92,6 +92,7 @@ void Initialize(void); /* function prototypes */
Boolean myFilterProc(DialogRef theDialog, EventRecord *theEvent, DialogItemIndex *itemHit);
int DeleteReceipt(void);
OSStatus CheckLogoutRequirement(int *finalAction);
+Boolean IsRestartNeeded();
void CheckUserAndGroupConflicts();
Boolean SetLoginItemOSAScript(long brandID, Boolean deleteLogInItem, char *userName);
Boolean SetLoginItemAPI(long brandID, Boolean deleteLogInItem);
@@ -424,14 +425,14 @@ int main(int argc, char *argv[])
pid_t waitPermissionsPID = 0;
uid_t saved_euid, saved_uid, b_m_uid;
passwd *pw;
- int finalInstallAction;
+ Boolean restartNeeded;
DialogRef theWin;
- err = CheckLogoutRequirement(&finalInstallAction);
- printf("CheckLogoutRequirement returned %d\n", finalInstallAction);
+ restartNeeded = IsRestartNeeded();
+ printf("IsRestartNeeded() returned %d\n", (int)restartNeeded);
fflush(stdout);
- if (finalInstallAction == launchWhenDone) {
+ if (!restartNeeded) {
// 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.
@@ -536,7 +537,7 @@ int DeleteReceipt()
int i;
pid_t installerPID = 0;
OSStatus err;
- int finalInstallAction;
+ Boolean restartNeeded = true;
FSRef fileRef;
char s[256];
struct stat sbuf;
@@ -544,8 +545,8 @@ int DeleteReceipt()
Initialize();
- err = CheckLogoutRequirement(&finalInstallAction);
-// print_to_log_file("CheckLogoutRequirement returned %d\n", finalInstallAction);
+ restartNeeded = IsRestartNeeded();
+// print_to_log_file("IsRestartNeeded() returned %d\n", (int)restartNeeded);
brandID = GetBrandID();
@@ -556,7 +557,7 @@ int DeleteReceipt()
// err_fsref = FSPathMakeRef((StringPtr)"/Applications/GridRepublic Desktop.app", &fileRef, NULL);
err_fsref = FSPathMakeRef((StringPtr)appPath[brandID], &fileRef, NULL);
- if (finalInstallAction == launchWhenDone) {
+ if (!restartNeeded) {
err = FindProcess ('APPL', 'xins', &installerPSN);
if (err == noErr) {
@@ -586,6 +587,21 @@ int DeleteReceipt()
}
+// BOINC Installer.app wrote a file to tell us whether a restart is required
+Boolean IsRestartNeeded() {
+ FILE *restartNeededFile;
+ int value;
+
+ restartNeededFile = fopen("/tmp/BOINC_restart_flag", "r");
+ if (restartNeededFile) {
+ fscanf(restartNeededFile,"%d", &value);
+ fclose(restartNeededFile);
+ return (value != 0);
+ }
+
+ return true;
+}
+
OSStatus CheckLogoutRequirement(int *finalAction)
{
*finalAction = restartRequired;
diff --git a/mac_installer/release_boinc.sh b/mac_installer/release_boinc.sh
index d14e40281b..841cde8d7e 100644
--- a/mac_installer/release_boinc.sh
+++ b/mac_installer/release_boinc.sh
@@ -275,6 +275,19 @@ if [ ! -d ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BO
fi
cp -fp mac_installer/Description.plist ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/BOINC.pkg/Contents/Resources/en.lproj/
+# Build the "BOINC.mpkg" metapackage (used if installer.app determines
+# that we need user to restart OS X after installation)
+mkdir -p "../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC Installer.app/Contents/Resources/BOINC.mpkg/Contents/Resources"
+cp -fp mac_build/Pkg_Restart-Info.plist ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/BOINC.mpkg/Contents/Info.plist
+cp -fp mac_installer/License.rtf ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/BOINC.mpkg/Contents/Resources/
+cp -fp ../BOINC_Installer/Installer\ Resources/ReadMe.rtf ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/BOINC.mpkg/Contents/Resources/
+cat >> ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/BOINC.mpkg/Contents/Resources/package_version << ENDOFFILE
+major: $1
+minor: $2
+ENDOFFILE
+echo "pmkrpkg1" > ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/BOINC.mpkg/Contents/PkgInfo
+
+
# Build the BOINC+VirtualBox.mpkg metapackage if VirtualBox.pkg exists
VirtualBoxPackageName="VirtualBox.pkg"
@@ -290,6 +303,12 @@ ENDOFFILE
echo "pmkrpkg1" > ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/BOINC+VirtualBox.mpkg/Contents/PkgInfo
cp -fpR mac_installer/${VirtualBoxPackageName} ../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC\ Installer.app/Contents/Resources/
+
+ # Now create the "BOINC+VirtualBox .mpkg" metapackage (used if installer.app
+ # determines that we need user to restart OS X after installation)
+ cp -fpR "../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC Installer.app/Contents/Resources/BOINC+VirtualBox.mpkg" "../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC Installer.app/Contents/Resources/BOINC+VirtualBox .mpkg"
+ # Change "NoRestart" to "RequiredRestart" in BOINC+VirtualBox .mpkg
+ sed -i "" s/"NoRestart"/"RequiredRestart"/g "../BOINC_Installer/New_Release_$1_$2_$3/boinc_$1.$2.$3_macOSX_$arch/BOINC Installer.app/Contents/Resources/BOINC+VirtualBox .mpkg/Contents/Info.plist"
fi
# Build the stand-alone client distribution