mirror of https://github.com/BOINC/boinc.git
Mac installer: update AddRemoveUser command-line utility for compatibility with OS 10.5 - OS 10.9
- eliminate obsolete LoginItemAPI code
This commit is contained in:
parent
c43398afc9
commit
7868584774
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
/* AddRemoveUser.cpp */
|
/* AddRemoveUser.cpp */
|
||||||
|
|
||||||
|
#define VERBOSE 0
|
||||||
|
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
|
|
||||||
#include <unistd.h> // getlogin
|
#include <unistd.h> // getlogin
|
||||||
|
@ -24,12 +26,13 @@
|
||||||
#include <pwd.h> // getpwname, getpwuid, getuid
|
#include <pwd.h> // getpwname, getpwuid, getuid
|
||||||
#include <grp.h> // getgrnam
|
#include <grp.h> // getgrnam
|
||||||
|
|
||||||
#include "LoginItemAPI.h" //please take a look at LoginItemAPI.h for an explanation of the routines available to you.
|
|
||||||
|
|
||||||
void printUsage(void);
|
void printUsage(void);
|
||||||
void SetLoginItem(Boolean addLogInItem);
|
Boolean SetLoginItemOSAScript(Boolean addLogInItem, char *userName);
|
||||||
static char * PersistentFGets(char *buf, size_t buflen, FILE *f);
|
static char * PersistentFGets(char *buf, size_t buflen, FILE *f);
|
||||||
static int compareOSVersionTo(int toMajor, int toMinor);
|
static int compareOSVersionTo(int toMajor, int toMinor);
|
||||||
|
OSErr FindProcess (OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN);
|
||||||
|
static void SleepTicks(UInt32 ticksToSleep);
|
||||||
|
static OSErr QuitOneProcess(OSType signature);
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -136,11 +139,12 @@ int main(int argc, char *argv[])
|
||||||
system(s);
|
system(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set or remove login item for this user
|
||||||
|
SetLoginItemOSAScript(AddUsers, pw->pw_name);
|
||||||
|
|
||||||
saved_uid = geteuid();
|
saved_uid = geteuid();
|
||||||
seteuid(pw->pw_uid); // Temporarily set effective uid to this user
|
seteuid(pw->pw_uid); // Temporarily set effective uid to this user
|
||||||
|
|
||||||
SetLoginItem(AddUsers); // Set or remove login item for this user
|
|
||||||
|
|
||||||
if (compareOSVersionTo(10, 6) < 0) {
|
if (compareOSVersionTo(10, 6) < 0) {
|
||||||
sprintf(s, "sudo -u %s defaults -currentHost read com.apple.screensaver moduleName",
|
sprintf(s, "sudo -u %s defaults -currentHost read com.apple.screensaver moduleName",
|
||||||
pw->pw_name);
|
pw->pw_name);
|
||||||
|
@ -208,38 +212,145 @@ void printUsage() {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetLoginItem(Boolean addLogInItem){
|
enum {
|
||||||
Boolean Success;
|
kSystemEventsCreator = 'sevs'
|
||||||
int NumberOfLoginItems, Counter;
|
};
|
||||||
char *p, *q;
|
|
||||||
|
|
||||||
Success = false;
|
Boolean SetLoginItemOSAScript(Boolean addLogInItem, char *userName)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
char cmd[2048];
|
||||||
|
char systemEventsPath[1024];
|
||||||
|
ProcessSerialNumber SystemEventsPSN;
|
||||||
|
FSRef appRef;
|
||||||
|
OSErr err, err2;
|
||||||
|
|
||||||
NumberOfLoginItems = GetCountOfLoginItems(kCurrentUser);
|
#if VERBOSE
|
||||||
|
fprintf(stderr, "Adjusting login items for user %s\n", userName);
|
||||||
|
fflush(stderr);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Search existing login items in reverse order, deleting any duplicates of ours
|
// We must launch the System Events application for the target user
|
||||||
for (Counter = NumberOfLoginItems ; Counter > 0 ; Counter--)
|
|
||||||
{
|
err = FindProcess ('APPL', kSystemEventsCreator, &SystemEventsPSN);
|
||||||
p = ReturnLoginItemPropertyAtIndex(kCurrentUser, kApplicationNameInfo, Counter-1);
|
if (err == noErr) {
|
||||||
if (p == NULL) continue;
|
// Find SystemEvents process. If found, quit it in case
|
||||||
q = p;
|
// it is running under a different user.
|
||||||
while (*q)
|
#if VERBOSE
|
||||||
{
|
fprintf(stderr, "Telling System Events to quit (at start of SetLoginItemOSAScript)\n");
|
||||||
// It is OK to modify the returned string because we "own" it
|
fflush(stderr);
|
||||||
*q = toupper(*q); // Make it case-insensitive
|
#endif
|
||||||
q++;
|
err = QuitOneProcess(kSystemEventsCreator);
|
||||||
|
if (err != noErr) {
|
||||||
|
fprintf(stderr, "QuitOneProcess(kSystemEventsCreator) returned error %d \n", (int) err);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
// Wait for the process to be gone
|
||||||
|
for (i=0; i<50; ++i) { // 5 seconds max delay
|
||||||
|
SleepTicks(6); // 6 Ticks == 1/10 second
|
||||||
|
err = FindProcess ('APPL', kSystemEventsCreator, &SystemEventsPSN);
|
||||||
|
if (err != noErr) break;
|
||||||
|
}
|
||||||
|
if (i >= 50) {
|
||||||
|
fprintf(stderr, "Failed to make System Events quit\n");
|
||||||
|
fflush(stderr);
|
||||||
|
err = noErr;
|
||||||
|
goto cleanupSystemEvents;
|
||||||
|
}
|
||||||
|
sleep(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(p, "BOINCMANAGER.APP") == 0) {
|
err = LSFindApplicationForInfo(kSystemEventsCreator, NULL, NULL, &appRef, NULL);
|
||||||
Success = RemoveLoginItemAtIndex(kCurrentUser, Counter-1);
|
if (err != noErr) {
|
||||||
|
fprintf(stderr, "LSFindApplicationForInfo(kSystemEventsCreator) returned error %d \n", (int) err);
|
||||||
|
fflush(stderr);
|
||||||
|
goto cleanupSystemEvents;
|
||||||
|
} else {
|
||||||
|
FSRefMakePath(&appRef, (UInt8*)systemEventsPath, sizeof(systemEventsPath));
|
||||||
|
#if VERBOSE
|
||||||
|
fprintf(stderr, "SystemEvents is at %s\n", systemEventsPath);
|
||||||
|
fprintf(stderr, "Launching SystemEvents for user %s\n", userName);
|
||||||
|
fflush(stderr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (j=0; j<5; ++j) {
|
||||||
|
sprintf(cmd, "sudo -u \"%s\" \"%s/Contents/MacOS/System Events\" &", userName, systemEventsPath);
|
||||||
|
err = system(cmd);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "Command: %s returned error %d (try %d of 5)\n", cmd, (int) err, j);
|
||||||
}
|
}
|
||||||
|
// Wait for the process to start
|
||||||
|
for (i=0; i<50; ++i) { // 5 seconds max delay
|
||||||
|
SleepTicks(6); // 6 Ticks == 1/10 second
|
||||||
|
err = FindProcess ('APPL', kSystemEventsCreator, &SystemEventsPSN);
|
||||||
|
if (err == noErr) break;
|
||||||
|
}
|
||||||
|
if (i < 50) break; // Exit j loop on success
|
||||||
|
}
|
||||||
|
if (j >= 5) {
|
||||||
|
fprintf(stderr, "Failed to launch System Events for user %s\n", userName);
|
||||||
|
fflush(stderr);
|
||||||
|
err = noErr;
|
||||||
|
goto cleanupSystemEvents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
#if VERBOSE
|
||||||
|
fprintf(stderr, "Deleting any login items containing BOINCManager for user %s\n", userName);
|
||||||
|
fflush(stderr);
|
||||||
|
#endif
|
||||||
|
sprintf(cmd, "sudo -u \"%s\" osascript -e 'tell application \"System Events\"' -e 'delete (every login item whose path contains \"BOINCManager\")' -e 'end tell'", userName);
|
||||||
|
err = system(cmd);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "Command: %s\n", cmd);
|
||||||
|
fprintf(stderr, "Delete login item containing \"BOINCManager\" returned error %d\n", err);
|
||||||
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addLogInItem) {
|
if (addLogInItem == false) {
|
||||||
Success = AddLoginItemWithPropertiesToUser(kCurrentUser, "/Applications/BOINCManager.app", kHideOnLaunch);
|
err = noErr;
|
||||||
|
goto cleanupSystemEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "Making new login item %s for user %s\n", "BOINCManager", userName);
|
||||||
|
fflush(stderr);
|
||||||
|
sprintf(cmd, "sudo -u \"%s\" osascript -e 'tell application \"System Events\"' -e 'make new login item at end with properties {path:\"/Applications/BOINCManager.app\", hidden:true, name:\"BOINCManager\"}' -e 'end tell'", userName);
|
||||||
|
err = system(cmd);
|
||||||
|
if (err) {
|
||||||
|
fprintf(stderr, "Command: %s\n", cmd);
|
||||||
|
printf("Make login item for %s returned error %d\n", "/Applications/BOINCManager.app", err);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
err2 = QuitOneProcess(kSystemEventsCreator);
|
||||||
|
if (err2 != noErr) {
|
||||||
|
fprintf(stderr, "QuitOneProcess(kSystemEventsCreator) returned error %d \n", (int) err2);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
// Wait for the process to be gone
|
||||||
|
for (i=0; i<50; ++i) { // 5 seconds max delay
|
||||||
|
SleepTicks(6); // 6 Ticks == 1/10 second
|
||||||
|
err2 = FindProcess ('APPL', kSystemEventsCreator, &SystemEventsPSN);
|
||||||
|
if (err2 != noErr) break;
|
||||||
|
}
|
||||||
|
if (i >= 50) {
|
||||||
|
fprintf(stderr, "Failed to make System Events quit\n");
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(4);
|
||||||
|
|
||||||
|
return (err == noErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static char * PersistentFGets(char *buf, size_t buflen, FILE *f) {
|
static char * PersistentFGets(char *buf, size_t buflen, FILE *f) {
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
size_t len = buflen;
|
size_t len = buflen;
|
||||||
|
@ -282,4 +393,114 @@ static int compareOSVersionTo(int toMajor, int toMinor) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/* This runs through the process list looking for the indicated application */
|
||||||
|
/* Searches for process by file type and signature (creator code) */
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
OSErr FindProcess (OSType typeToFind, OSType creatorToFind, ProcessSerialNumberPtr processSN)
|
||||||
|
{
|
||||||
|
ProcessInfoRec tempInfo;
|
||||||
|
FSSpec procSpec;
|
||||||
|
Str31 processName;
|
||||||
|
OSErr myErr = noErr;
|
||||||
|
/* null out the PSN so we're starting at the beginning of the list */
|
||||||
|
processSN->lowLongOfPSN = kNoProcess;
|
||||||
|
processSN->highLongOfPSN = kNoProcess;
|
||||||
|
/* initialize the process information record */
|
||||||
|
tempInfo.processInfoLength = sizeof(ProcessInfoRec);
|
||||||
|
tempInfo.processName = processName;
|
||||||
|
tempInfo.processAppSpec = &procSpec;
|
||||||
|
/* loop through all the processes until we */
|
||||||
|
/* 1) find the process we want */
|
||||||
|
/* 2) error out because of some reason (usually, no more processes) */
|
||||||
|
do {
|
||||||
|
myErr = GetNextProcess(processSN);
|
||||||
|
if (myErr == noErr)
|
||||||
|
GetProcessInformation(processSN, &tempInfo);
|
||||||
|
}
|
||||||
|
while ((tempInfo.processSignature != creatorToFind || tempInfo.processType != typeToFind) &&
|
||||||
|
myErr == noErr);
|
||||||
|
return(myErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Uses usleep to sleep for full duration even if a signal is received
|
||||||
|
static void SleepTicks(UInt32 ticksToSleep) {
|
||||||
|
UInt32 endSleep, timeNow, ticksRemaining;
|
||||||
|
|
||||||
|
timeNow = TickCount();
|
||||||
|
ticksRemaining = ticksToSleep;
|
||||||
|
endSleep = timeNow + ticksToSleep;
|
||||||
|
while ( (timeNow < endSleep) && (ticksRemaining <= ticksToSleep) ) {
|
||||||
|
usleep(16667 * ticksRemaining);
|
||||||
|
timeNow = TickCount();
|
||||||
|
ticksRemaining = endSleep - timeNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSErr QuitOneProcess(OSType signature) {
|
||||||
|
bool done = false;
|
||||||
|
ProcessSerialNumber thisPSN;
|
||||||
|
ProcessInfoRec thisPIR;
|
||||||
|
OSErr err = noErr;
|
||||||
|
Str63 thisProcessName;
|
||||||
|
AEAddressDesc thisPSNDesc;
|
||||||
|
AppleEvent thisQuitEvent, thisReplyEvent;
|
||||||
|
|
||||||
|
|
||||||
|
thisPIR.processInfoLength = sizeof (ProcessInfoRec);
|
||||||
|
thisPIR.processName = thisProcessName;
|
||||||
|
thisPIR.processAppSpec = nil;
|
||||||
|
|
||||||
|
thisPSN.highLongOfPSN = 0;
|
||||||
|
thisPSN.lowLongOfPSN = kNoProcess;
|
||||||
|
|
||||||
|
while (done == false) {
|
||||||
|
err = GetNextProcess(&thisPSN);
|
||||||
|
if (err == procNotFound) {
|
||||||
|
done = true; // Finished stepping through all running applications.
|
||||||
|
err = noErr; // Success
|
||||||
|
} else {
|
||||||
|
err = GetProcessInformation(&thisPSN,&thisPIR);
|
||||||
|
if (err != noErr)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
if (thisPIR.processSignature == signature) { // is it our target process?
|
||||||
|
err = AECreateDesc(typeProcessSerialNumber, (Ptr)&thisPSN,
|
||||||
|
sizeof(thisPSN), &thisPSNDesc);
|
||||||
|
if (err != noErr)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
// Create the 'quit' Apple event for this process.
|
||||||
|
err = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &thisPSNDesc,
|
||||||
|
kAutoGenerateReturnID, kAnyTransactionID, &thisQuitEvent);
|
||||||
|
if (err != noErr) {
|
||||||
|
AEDisposeDesc (&thisPSNDesc);
|
||||||
|
goto bail; // don't know how this could happen, but limp gamely onward
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the event
|
||||||
|
err = AESend(&thisQuitEvent, &thisReplyEvent, kAEWaitReply,
|
||||||
|
kAENormalPriority, kAEDefaultTimeout, 0L, 0L);
|
||||||
|
AEDisposeDesc (&thisQuitEvent);
|
||||||
|
AEDisposeDesc (&thisPSNDesc);
|
||||||
|
|
||||||
|
if (err != noErr)
|
||||||
|
goto bail;
|
||||||
|
#if 0
|
||||||
|
if (err == errAETimeout) {
|
||||||
|
pid_t thisPID;
|
||||||
|
|
||||||
|
err = GetProcessPID(&thisPSN , &thisPID);
|
||||||
|
if (err == noErr)
|
||||||
|
err = kill(thisPID, SIGKILL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
continue; // There can be multiple instances of the Manager
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bail:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue