mirror of https://github.com/BOINC/boinc.git
Further work on BONC Mac uninstaller
svn path=/trunk/boinc/; revision=12843
This commit is contained in:
parent
50d6ed1b94
commit
b9e73c2379
|
@ -5792,7 +5792,7 @@ Charlie 6 June 2007
|
|||
- Mac: Create "Uninstall BOINC" application, modify build scripts
|
||||
to include it in release package with BOINC Manager.
|
||||
- Mac: Fix a bug in release_GridRepublic.sh build script which
|
||||
created a boogus " BOINC Data/locale" directory (with a bad
|
||||
created a bogus " BOINC Data/locale" directory (with a bad
|
||||
leading space character.)
|
||||
|
||||
mac_build/
|
||||
|
@ -5871,3 +5871,15 @@ Rom 6 June 2007
|
|||
boinccas.dll
|
||||
boinccas95.dll
|
||||
|
||||
Charlie 7 June 2007
|
||||
- Mac: Further work on "Uninstall BOINC" application: use various
|
||||
techniques to try to locate BOINC Manager in non-standard
|
||||
directories, use branding-independent search techniques.
|
||||
to include it in release package with BOINC Manager.
|
||||
|
||||
mac_build/
|
||||
boinc.xcodeproj/
|
||||
project.pbxproj
|
||||
Uninstaller-Info.plist
|
||||
mac_installer/
|
||||
uninstall.cpp
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>Uninstall BOINC version 5.10.2, Copyright 2007 University of California.</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>edu.berkeley.boinc.Uninstaller</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
|
@ -16,5 +18,11 @@
|
|||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.10.2</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Uninstall BOINC</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>Uninstall BOINC version 5.10.2</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -239,7 +239,6 @@
|
|||
DDAEC9FF07FA5A5C00A7BC36 /* SetVersion.C in Sources */ = {isa = PBXBuildFile; fileRef = DDAEC9E707FA58A000A7BC36 /* SetVersion.C */; };
|
||||
DDB693500ABFE9C600689FD8 /* procinfo_mac.C in Sources */ = {isa = PBXBuildFile; fileRef = DDB6934F0ABFE9C600689FD8 /* procinfo_mac.C */; };
|
||||
DDBD51760C169B770074905B /* LoginItemAPI.c in Sources */ = {isa = PBXBuildFile; fileRef = DD1277BE081F3E73007B5DE1 /* LoginItemAPI.c */; };
|
||||
DDBD52BD0C16C7180074905B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F51BDF4903086C46012012A7 /* InfoPlist.strings */; };
|
||||
DDBE74390C03B1C600453BB8 /* cs_platforms.C in Sources */ = {isa = PBXBuildFile; fileRef = DDBE74380C03B1C600453BB8 /* cs_platforms.C */; };
|
||||
DDCDCDF60B532433009BB03C /* ViewProjectsGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DDCDCDF20B532433009BB03C /* ViewProjectsGrid.cpp */; };
|
||||
DDD095490A3EDF2D00C95BA4 /* switcher.C in Sources */ = {isa = PBXBuildFile; fileRef = DDD095480A3EDF2D00C95BA4 /* switcher.C */; };
|
||||
|
@ -2252,7 +2251,6 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DDBD52BD0C16C7180074905B /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -35,16 +35,17 @@
|
|||
#include "LoginItemAPI.h" //please take a look at LoginItemAPI.h for an explanation of the routines available to you.
|
||||
|
||||
static OSStatus DoUninstall(void);
|
||||
static OSErr CleanupAllVisibleUsers(void);
|
||||
static OSStatus GetpathToBOINCManagerApp(char* path, int maxLen, FSRef *theFSRef);
|
||||
static OSStatus CleanupAllVisibleUsers(void);
|
||||
static OSStatus DeleteOurBundlesFromDirectory(CFStringRef bundleID, char *extension, char *dirPath);
|
||||
static OSStatus GetAuthorization(AuthorizationRef * authRef, const char *pathToTool, char *brandName);
|
||||
static OSStatus DoPrivilegedExec(char *brandName, const char *pathToTool, char *arg1, char *arg2, char *arg3, char *arg4, char *arg5);
|
||||
static void DeleteLoginItem(void);
|
||||
static char * PersistentFGets(char *buf, size_t buflen, FILE *f);
|
||||
static pid_t FindProcessPID(char* name, pid_t thePID);
|
||||
static OSErr QuitBOINCManager(OSType signature);
|
||||
static OSStatus QuitBOINCManager(OSType signature);
|
||||
static void SleepTicks(UInt32 ticksToSleep);
|
||||
static void ShowMessage(const char *format, ...);
|
||||
static pascal Boolean ErrorDlgFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *theItemHit);
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -91,7 +92,7 @@ int main(int argc, char *argv[])
|
|||
strlcat(pathToSelf, "/Contents/MacOS/", sizeof(pathToSelf));
|
||||
strlcat(pathToSelf, appName, sizeof(pathToSelf));
|
||||
|
||||
p = strrchr(appName, ' ');
|
||||
p = strchr(appName, ' ');
|
||||
p += 1; // Point to brand name following "Uninstall "
|
||||
|
||||
err = DoPrivilegedExec(p, pathToSelf, "--privileged", NULL, NULL, NULL, NULL);
|
||||
|
@ -115,6 +116,11 @@ int main(int argc, char *argv[])
|
|||
|
||||
static OSStatus DoUninstall(void) {
|
||||
pid_t coreClientPID = 0;
|
||||
char myRmCommand[MAXPATHLEN+10], plistRmCommand[MAXPATHLEN+10], *p;
|
||||
char notBoot[] = "/Volumes/";
|
||||
FSRef theFSRef;
|
||||
int pathOffset, i;
|
||||
OSStatus err = noErr;
|
||||
|
||||
#if TESTING
|
||||
ShowMessage("Permission OK after relaunch");
|
||||
|
@ -128,32 +134,199 @@ static OSStatus DoUninstall(void) {
|
|||
if (coreClientPID)
|
||||
kill(coreClientPID, SIGTERM); // boinc catches SIGTERM & exits gracefully
|
||||
|
||||
// Phase 1: try to find all our applications using LaunchServices
|
||||
for (i=0; i<100; i++) {
|
||||
strlcpy(myRmCommand, "rm -rf \"", 10);
|
||||
pathOffset = strlen(myRmCommand);
|
||||
|
||||
err = GetpathToBOINCManagerApp(myRmCommand+pathOffset, MAXPATHLEN, &theFSRef);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
strlcat(myRmCommand, "\"", sizeof(myRmCommand));
|
||||
|
||||
#if TESTING
|
||||
ShowMessage("manager: %s", myRmCommand);
|
||||
#endif
|
||||
|
||||
p = strstr(myRmCommand, notBoot);
|
||||
|
||||
if (p == myRmCommand+pathOffset) {
|
||||
#if TESTING
|
||||
ShowMessage("Not on boot volume: %s", myRmCommand);
|
||||
#endif
|
||||
break;
|
||||
} else {
|
||||
|
||||
// First delete just the application's info.plist file and update the
|
||||
// LaunchServices Database;; otherwise LSFindApplicationForInfo might
|
||||
// return this application again after it's been deleted.
|
||||
strlcpy(plistRmCommand, myRmCommand, sizeof(plistRmCommand));
|
||||
strlcat(plistRmCommand, "/Contents/info.plist", sizeof(plistRmCommand));
|
||||
#if TESTING
|
||||
ShowMessage("Deleting info.plist: %s", plistRmCommand);
|
||||
#endif
|
||||
system(plistRmCommand);
|
||||
err = LSRegisterFSRef(&theFSRef, true);
|
||||
#if TESTING
|
||||
if (err)
|
||||
ShowMessage("LSRegisterFSRef returned error %d", err);
|
||||
#endif
|
||||
system(myRmCommand);
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: step through default Applications directory searching for our applications
|
||||
err = DeleteOurBundlesFromDirectory(CFSTR("edu.berkeley.boinc"), "app", "/Applications");
|
||||
|
||||
// Phase 3: step through default Screen Savers directory searching for our screen savers
|
||||
err = DeleteOurBundlesFromDirectory(CFSTR("edu.berkeley.boincsaver"), "saver", "/Library/Screen Savers");
|
||||
|
||||
// Phase 4: Delete our files and directories at our installer's default locations
|
||||
// Remove everything we've installed, whether BOINC or GridRepublic
|
||||
// These first 4 should already have been deleted by the above code, but do them anyway for safety
|
||||
system ("rm -rf /Applications/BOINCManager.app");
|
||||
system ("rm -rf \"/Library/Screen Savers/BOINCSaver.saver\"");
|
||||
system ("rm -rf /Library/Receipts/BOINC.pkg");
|
||||
|
||||
system ("rm -rf \"/Applications/GridRepublic Desktop.app\"");
|
||||
system ("rm -rf \"/Library/Screen Savers/GridRepublic.saver\"");
|
||||
|
||||
|
||||
system ("rm -rf /Library/Receipts/GridRepublic.pkg");
|
||||
system ("rm -rf /Library/Receipts/BOINC.pkg");
|
||||
|
||||
// We don't customize BOINC Data directory name for branding
|
||||
system ("rm -rf \"/Library/Application Support/BOINC Data\"");
|
||||
|
||||
// Phase 5: step through all users and do user-specific cleanup
|
||||
CleanupAllVisibleUsers();
|
||||
|
||||
system ("dscl . -delete /users/boinc_master");
|
||||
system ("dscl . -delete /groups/boinc_master");
|
||||
system ("dscl . -delete /users/boinc_project");
|
||||
system ("dscl . -delete /groups/boinc_project");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static OSStatus GetpathToBOINCManagerApp(char* path, int maxLen, FSRef *theFSRef)
|
||||
{
|
||||
CFStringRef bundleID = CFSTR("edu.berkeley.boinc");
|
||||
OSType creator = 'BNC!';
|
||||
OSStatus status = noErr;
|
||||
|
||||
status = LSFindApplicationForInfo(creator, bundleID, NULL, theFSRef, NULL);
|
||||
if (status) {
|
||||
#if TESTING
|
||||
ShowMessage("LSFindApplicationForInfo returned error %d", status);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
status = FSRefMakePath(theFSRef, (unsigned char *)path, maxLen);
|
||||
#if TESTING
|
||||
if (status)
|
||||
ShowMessage("GetpathToBOINCManagerApp FSRefMakePath returned error %d, %s", status, path);
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static OSStatus DeleteOurBundlesFromDirectory(CFStringRef bundleID, char *extension, char *dirPath) {
|
||||
DIR *dirp;
|
||||
dirent *dp;
|
||||
CFStringRef urlStringRef = NULL;
|
||||
int index;
|
||||
CFStringRef thisID = NULL;
|
||||
CFBundleRef thisBundle = NULL;
|
||||
CFURLRef bundleURLRef = NULL;
|
||||
char myRmCommand[MAXPATHLEN+10], *p;
|
||||
int pathOffset;
|
||||
|
||||
dirp = opendir(dirPath);
|
||||
if (dirp == NULL) { // Should never happen
|
||||
ShowMessage("opendir(\"%s\") failed", dirPath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
while (true) {
|
||||
index++;
|
||||
|
||||
dp = readdir(dirp);
|
||||
if (dp == NULL)
|
||||
break; // End of list
|
||||
|
||||
p = strrchr(dp->d_name, '.');
|
||||
if (p == NULL)
|
||||
continue;
|
||||
|
||||
if (strcmp(p+1, extension))
|
||||
continue;
|
||||
|
||||
strlcpy(myRmCommand, "rm -rf \"", 10);
|
||||
pathOffset = strlen(myRmCommand);
|
||||
strlcat(myRmCommand, dirPath, sizeof(myRmCommand));
|
||||
strlcat(myRmCommand, "/", sizeof(myRmCommand));
|
||||
strlcat(myRmCommand, dp->d_name, sizeof(myRmCommand));
|
||||
urlStringRef = CFStringCreateWithCString(kCFAllocatorDefault, myRmCommand+pathOffset, CFStringGetSystemEncoding());
|
||||
if (urlStringRef) {
|
||||
bundleURLRef = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlStringRef, kCFURLPOSIXPathStyle, false);
|
||||
if (bundleURLRef) {
|
||||
thisBundle = CFBundleCreate( kCFAllocatorDefault, bundleURLRef );
|
||||
if (thisBundle) {
|
||||
thisID = CFBundleGetIdentifier(thisBundle);
|
||||
if (thisID) {
|
||||
strlcat(myRmCommand, "\"", sizeof(myRmCommand));
|
||||
if (CFStringCompare(thisID, bundleID, 0) == kCFCompareEqualTo) {
|
||||
#if TESTING
|
||||
ShowMessage("Bundles: %s", myRmCommand);
|
||||
#endif
|
||||
|
||||
system(myRmCommand);
|
||||
} else {
|
||||
#if TESTING
|
||||
// ShowMessage("Bundles: Not deleting %s", myRmCommand+pathOffset);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // if (thisID)
|
||||
#if TESTING
|
||||
else
|
||||
ShowMessage("CFBundleGetIdentifier failed for index %d", index);
|
||||
#endif
|
||||
CFRelease(thisBundle);
|
||||
} //if (thisBundle)
|
||||
#if TESTING
|
||||
else
|
||||
ShowMessage("CFBundleCreate failed for index %d", index);
|
||||
#endif
|
||||
CFRelease(bundleURLRef);
|
||||
} // if (bundleURLRef)
|
||||
#if TESTING
|
||||
else
|
||||
ShowMessage("CFURLCreateWithFileSystemPath failed");
|
||||
#endif
|
||||
|
||||
CFRelease(urlStringRef);
|
||||
} // if (urlStringRef)
|
||||
#if TESTING
|
||||
else
|
||||
ShowMessage("CFStringCreateWithCString failed");
|
||||
#endif
|
||||
} // while true
|
||||
|
||||
closedir(dirp);
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
// Find all visible users and delete their login item to launch BOINC Manager.
|
||||
// Remove each user from groups boinc_master and boinc_project.
|
||||
// Delete user's BOINC Preferences file.
|
||||
static OSErr CleanupAllVisibleUsers(void)
|
||||
static OSStatus CleanupAllVisibleUsers(void)
|
||||
{
|
||||
DIR *dirp;
|
||||
dirent *dp;
|
||||
|
@ -414,11 +587,11 @@ static pid_t FindProcessPID(char* name, pid_t thePID)
|
|||
}
|
||||
|
||||
|
||||
static OSErr QuitBOINCManager(OSType signature) {
|
||||
static OSStatus QuitBOINCManager(OSType signature) {
|
||||
bool done = false;
|
||||
ProcessSerialNumber thisPSN;
|
||||
ProcessInfoRec thisPIR;
|
||||
OSErr err = noErr;
|
||||
OSStatus err = noErr;
|
||||
Str63 thisProcessName;
|
||||
AEAddressDesc thisPSNDesc;
|
||||
AppleEvent thisQuitEvent, thisReplyEvent;
|
||||
|
@ -497,7 +670,7 @@ static void ShowMessage(const char *format, ...) {
|
|||
char s[1024];
|
||||
short itemHit;
|
||||
AlertStdAlertParamRec alertParams;
|
||||
ModalFilterUPP ErrorDlgFilterProcUPP;
|
||||
// ModalFilterUPP ErrorDlgFilterProcUPP;
|
||||
|
||||
ProcessSerialNumber ourProcess;
|
||||
|
||||
|
@ -505,11 +678,12 @@ static void ShowMessage(const char *format, ...) {
|
|||
s[0] = vsprintf(s+1, format, args);
|
||||
va_end(args);
|
||||
|
||||
ErrorDlgFilterProcUPP = NewModalFilterUPP(ErrorDlgFilterProc);
|
||||
// ErrorDlgFilterProcUPP = NewModalFilterUPP(ErrorDlgFilterProc);
|
||||
|
||||
alertParams.movable = true;
|
||||
alertParams.helpButton = false;
|
||||
alertParams.filterProc = ErrorDlgFilterProcUPP;
|
||||
// alertParams.filterProc = ErrorDlgFilterProcUPP;
|
||||
alertParams.filterProc = NULL;
|
||||
alertParams.defaultText = "\pOK";
|
||||
alertParams.cancelText = NULL;
|
||||
alertParams.otherText = NULL;
|
||||
|
@ -521,18 +695,4 @@ static void ShowMessage(const char *format, ...) {
|
|||
::SetFrontProcess(&ourProcess);
|
||||
|
||||
StandardAlert (kAlertStopAlert, (StringPtr)s, NULL, &alertParams, &itemHit);
|
||||
|
||||
DisposeModalFilterUPP(ErrorDlgFilterProcUPP);
|
||||
}
|
||||
|
||||
|
||||
static pascal Boolean ErrorDlgFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *theItemHit) {
|
||||
// We need this because this is a command-line application so it does not get normal events
|
||||
if (Button()) {
|
||||
*theItemHit = kStdOkItemIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
return StdFilterProc(theDialog, theEvent, theItemHit);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue