Esempio n. 1
0
/*
 * Wait until a console user logs in (or don't wait if one is already logged in).
 */
static bool
wait_for_console_user(char *devname)
{
	CFStringRef             key;
	CFMutableArrayRef       keys;
	Boolean                 ok;
	SCDynamicStoreRef       store = NULL;
	CFRunLoopSourceRef      rls;
	CFStringRef             user;
	uid_t                   uid;
	gid_t                   gid;
	bool                    ret = false;

	store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.nofs"),
	    console_user_changed_cb, NULL);
	if (store == NULL) {
		return ret;
	}

	/* check if a console user is already logged in */
	user = SCDynamicStoreCopyConsoleUser(store, &uid, &gid);
	if (user != NULL) {
		CFRelease(user);
		ret = true;
		goto out;
	}

	/* wait for a notification that a console user logged in */
	keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	key = SCDynamicStoreKeyCreateConsoleUser(NULL);
	CFArrayAppendValue(keys, key);
	CFRelease(key);
	ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
	CFRelease(keys);
	if (!ok) {
		syslog(LOG_ERR, "nofs: SCDynamicStoreSetNotificationKeys() failed");
		goto out;
	}
	rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
	if (rls == NULL) {
		syslog(LOG_ERR, "nofs: SCDynamicStoreCreateRunLoopSource() failed");
		goto out;
	}

	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
	CFRunLoopRun();
	CFRunLoopSourceInvalidate(rls);
	CFRelease(rls);

	ret = true;

out:
	if (store) {
		CFRelease(store);
	}
	return ret;
}
Esempio n. 2
0
void LoginLogoutCallBackFunction(SCDynamicStoreRef store, CFArrayRef changedKeys, void * info)
{
    CFStringRef	consoleUserName;
    consoleUserName = SCDynamicStoreCopyConsoleUser(store, NULL, NULL);
    if (consoleUserName != NULL)
    {
		stamp_file(CFStringCreateWithFormat(NULL, NULL, CFSTR("User '%@' has logged in"), consoleUserName));
        CFRelease(consoleUserName);
    }
}
Esempio n. 3
0
static void
console_user_changed_cb(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
    CFStringRef                 user;
    uid_t                       uid;
    gid_t                       gid;

    user = SCDynamicStoreCopyConsoleUser(store, &uid, &gid);
    if (user != NULL) {
        CFRelease(user);
		CFRunLoopStop(CFRunLoopGetCurrent());
    }
}
Esempio n. 4
0
/* @function SystemLoadUserStateHasChanged
 * Populates:
 *  loggedInUser
 *  loggedInUserIdle
 *  switchedOutUsers
 *  remoteConnections
 */
__private_extern__ void SystemLoadUserStateHasChanged(void)
{
    CFStringRef         loggedInUserName;

    loggedInUser = false;

    loggedInUserName = SCDynamicStoreCopyConsoleUser(_getSharedPMDynamicStore(),
                                                    NULL,  // uid
                                                    NULL); // gid
    if (loggedInUserName) {
        loggedInUser = true;
        CFRelease(loggedInUserName);
    }

    shareTheSystemLoad(kYesNotify);
}
Esempio n. 5
0
static void ServiceMatchedCallbackFunction(void * context, 
											io_iterator_t iter) {
	io_object_t		ioObject;
	Boolean			anyMatched = FALSE;
    uid_t			uid;
    gid_t			gid;

	if(consoleUser != NULL) {
		CFRelease(consoleUser);
		consoleUser = NULL;
	}
	
	while((ioObject = IOIteratorNext(iter)) != 0) {
		anyMatched = TRUE;
		IOObjectRelease(ioObject);
	}
	
	if(anyMatched == TRUE) {
		write_log(LOG_NOTICE, "Service '" kDriverClassName "' matched.");

		if(dsSession == NULL && 
			(InitDynamicStore() == FALSE ||
				RegisterConsoleUserChangeCallback() == FALSE)) {
			write_log(LOG_ERR, "Unable to initiate session!");
			kill(getpid(), SIGTERM);
		} else {
			const char * name;
			consoleUser = SCDynamicStoreCopyConsoleUser(dsSession, &uid, &gid);
			if(consoleUser != NULL) {
				name = CFStringGetCStringPtr(consoleUser, 
												kCFStringEncodingMacRoman);
				write_log(LOG_NOTICE, "User '%s' is logged in.", name);
			} else
				write_log(LOG_NOTICE, "No user is logged in.");

			if(uid == getuid())
				LoadSettingsForUser(consoleUser);
			else if(consoleUser != NULL)
				write_log(LOG_NOTICE,
							"Not updating settings as this instance of %s does "
							"not handle user '%s'.", 
							kProgramName, name);
		}
	} else
		write_log(LOG_WARNING, "Service '%s' not matched!", kDriverClassName);
}
Esempio n. 6
0
static void SignalHandlerFunction(int signo) {
    uid_t		uid;
    gid_t		gid;
	const char	*name;
	
	write_log(LOG_NOTICE, "Received signal %d.", signo);
	switch(signo) {
		case SIGINT:
		case SIGTERM:
			CFRunLoopStop(CFRunLoopGetCurrent());
			break;
		case SIGHUP:
			consoleUser = SCDynamicStoreCopyConsoleUser(dsSession, &uid, &gid);
			if (consoleUser != NULL)
				name = CFStringGetCStringPtr(consoleUser, 
												kCFStringEncodingMacRoman);
			if(uid == getuid())
				LoadSettingsForUser(consoleUser);
			else if(consoleUser != NULL)
				write_log(LOG_NOTICE, "Not updating settings as this instance "
							"of %s does not handle user '%s'.",
							kProgramName, name);
			break;
		case SIGINFO:
			write_log(LOG_NOTICE, "%s %s", kProgramName, kProgramVersion);
			if(consoleUser != NULL)
				name = CFStringGetCStringPtr(consoleUser,
												kCFStringEncodingMacRoman);
			write_log(LOG_NOTICE, "dsSession = '%d'", dsSession);
			write_log(LOG_NOTICE, "dsRunLoopSource = '%d'", dsRunLoopSource);
			write_log(LOG_NOTICE, "ioKitNotificationPort = '%d'", 
					ioKitNotificationPort);
			write_log(LOG_NOTICE, "ioRunLoopSource = '%d'", ioRunLoopSource);
			if(consoleUser != NULL)
				write_log(LOG_NOTICE, "consoleUser = '******'", name);
			else
				write_log(LOG_NOTICE, "consoleUser = NULL");
	}
}
Esempio n. 7
0
static void ConsoleUserChangedCallbackFunction(SCDynamicStoreRef store, 
											   CFArrayRef changedKeys, 
											   void * context) {
	const char			* oldName;
	const char			* newName;
    uid_t				uid;
    gid_t				gid;
	CFStringRef			newConsoleUser;
	
	newConsoleUser = SCDynamicStoreCopyConsoleUser(store, &uid, &gid);

	if(consoleUser != NULL)
		oldName = CFStringGetCStringPtr(consoleUser, kCFStringEncodingMacRoman);
	
	if(newConsoleUser != NULL) {
		newName = CFStringGetCStringPtr(newConsoleUser, 
										kCFStringEncodingMacRoman);
										
		if(consoleUser != NULL) {
			write_log(LOG_NOTICE, "Console user changed from '%s' to '%s'.", 
					oldName, newName);
		} else
			write_log(LOG_NOTICE, "Console user '%s' logged in.", newName); 
			
	} else if(consoleUser != NULL)
		write_log(LOG_NOTICE, "Console user '%s' logged out.", oldName);

	if(consoleUser != NULL) {
		CFRelease(consoleUser);
		consoleUser = NULL;
	}
	consoleUser = newConsoleUser;
	if(uid == getuid())
		LoadSettingsForUser(newConsoleUser);
	else if(newConsoleUser != NULL)
		write_log(LOG_NOTICE, "Not updating settings as this instance of %s "
								"does not handle user '%s'.", 
								kProgramName, newName);
}
PsychError SCREENComputer(void) 
{
    const char *majorStructFieldNames[]={"macintosh", "windows", "osx" ,"linux", "kern", "hw", "processUserLongName", 
	                                     "processUserShortName", "consoleUserName", "machineName", "localHostName", "location", "MACAddress", "system" };
    const char *kernStructFieldNames[]={"ostype", "osrelease", "osrevision", "version","hostname"};
    const char *hwStructFieldNames[]={"machine", "model", "ncpu", "physmem", "usermem", "busfreq", "cpufreq"};
    int numMajorStructDimensions=1, numKernStructDimensions=1, numHwStructDimensions=1;
    int numMajorStructFieldNames=14, numKernStructFieldNames=5, numHwStructFieldNames=7;
    PsychGenericScriptType	*kernStruct, *hwStruct, *majorStruct;
    //char tempStr[CTL_MAXNAME];   //this seems like a bug in Darwin, CTL_MAXNAME is shorter than the longest name.  
    char						tempStr[256], *ethernetMACStr;
    size_t						tempIntSize,  tempStrSize, tempULongIntSize; 	
	int							mib[2];
	int							tempInt;
	unsigned long int			tempULongInt;
	char						*tempStrPtr;
	CFStringRef					tempCFStringRef;
	psych_bool						stringSuccess;
	int							stringLengthChars, ethernetMACStrSizeBytes;
	long						gestaltResult;
	OSErr						gestaltError;
//	Str255						systemVersionStr, systemVersionStrForward;
	int							i,strIndex, bcdDigit, lengthSystemVersionString;
	long						osMajor, osMinor, osBugfix;
	char						systemVersionStr[256];
	
    //all subfunctions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(0));

    //fill the major struct 
    PsychAllocOutStructArray(1, FALSE, numMajorStructDimensions, numMajorStructFieldNames, majorStructFieldNames, &majorStruct);
    PsychSetStructArrayDoubleElement("macintosh", 0, 0, majorStruct);
    PsychSetStructArrayDoubleElement("windows", 0, 0, majorStruct);
    PsychSetStructArrayDoubleElement("linux", 0, 0, majorStruct);
    PsychSetStructArrayDoubleElement("osx", 0, 1, majorStruct);

    //fill the kern struct and implant it within the major struct
    PsychAllocOutStructArray(-1, FALSE, numKernStructDimensions, numKernStructFieldNames, kernStructFieldNames, &kernStruct);
    mib[0]=CTL_KERN;

    mib[1]=KERN_OSTYPE;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("ostype", 0, tempStr, kernStruct);

    mib[1]=KERN_OSRELEASE;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("osrelease", 0, tempStr, kernStruct);

    mib[1]=KERN_OSREV;
    tempIntSize=sizeof(tempInt);
    ReportSysctlError(sysctl(mib, 2, &tempInt, &tempIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("osrevision", 0, (double)tempInt, kernStruct);

    mib[1]=KERN_VERSION;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("version", 0, tempStr, kernStruct);

    mib[1]=KERN_HOSTNAME;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("hostname", 0, tempStr, kernStruct);
    PsychSetStructArrayStructElement("kern",0, kernStruct, majorStruct);

    //fill the hw struct and implant it within the major struct
    PsychAllocOutStructArray(-1, FALSE, numHwStructDimensions, numHwStructFieldNames, hwStructFieldNames, &hwStruct);
    mib[0]=CTL_HW;

    mib[1]=HW_MACHINE;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("machine", 0, tempStr, hwStruct);

    mib[1]=HW_MODEL;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("model", 0, tempStr, hwStruct);

    mib[1]=HW_NCPU;
    tempIntSize=sizeof(tempInt);
    ReportSysctlError(sysctl(mib, 2, &tempInt, &tempIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("ncpu", 0, (double)tempInt, hwStruct);

    mib[1]=HW_MEMSIZE;
    long long tempLongInt;
    tempULongIntSize=sizeof(tempLongInt);
    ReportSysctlError(sysctl(mib, 2, &tempLongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("physmem", 0, (double)tempLongInt, hwStruct);

    mib[1]=HW_USERMEM;
    tempULongIntSize=sizeof(tempULongInt);
    ReportSysctlError(sysctl(mib, 2, &tempULongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("usermem", 0, (double)tempULongInt, hwStruct);

    mib[1]=HW_BUS_FREQ;
    tempULongIntSize=sizeof(tempULongInt);
    ReportSysctlError(sysctl(mib, 2, &tempULongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("busfreq", 0, (double)tempULongInt, hwStruct);

    mib[1]=HW_CPU_FREQ;
    tempULongIntSize=sizeof(tempULongInt);
    ReportSysctlError(sysctl(mib, 2, &tempULongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("cpufreq", 0, (double)tempULongInt, hwStruct);
    PsychSetStructArrayStructElement("hw",0, hwStruct, majorStruct);

    //fill in the process user, console user and machine name in the root struct.
	tempCFStringRef= CSCopyMachineName();
	if (tempCFStringRef) {
		stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingUTF8);
		tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
		stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingUTF8);
		
		if(stringSuccess) {
            PsychSetStructArrayStringElement("machineName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("machineName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }
        
		free(tempStrPtr);
		CFRelease(tempCFStringRef);
	}
	else {
		PsychSetStructArrayStringElement("machineName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
	}
	
	tempCFStringRef= CSCopyUserName(TRUE); //use short name
	if (tempCFStringRef) {		
		stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingUTF8);
		tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
		stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingUTF8);
		if(stringSuccess) {
            PsychSetStructArrayStringElement("processUserShortName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("processUserShortName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }
		
		free(tempStrPtr);
		CFRelease(tempCFStringRef);
	}
	else {
		PsychSetStructArrayStringElement("processUserShortName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
	}

	tempCFStringRef= CSCopyUserName(FALSE); //use long name
	if (tempCFStringRef) {		
		stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingUTF8);
		tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
		stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingUTF8);
		if(stringSuccess) {
            PsychSetStructArrayStringElement("processUserLongName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("processUserLongName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }

		free(tempStrPtr);
		CFRelease(tempCFStringRef);
	}
	else {
		PsychSetStructArrayStringElement("processUserLongName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
	}
	
	tempCFStringRef= SCDynamicStoreCopyConsoleUser(NULL, NULL, NULL);
	if (tempCFStringRef) {
		stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingUTF8);
		tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
		stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingUTF8);
		
		if(stringSuccess) {
            PsychSetStructArrayStringElement("consoleUserName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("consoleUserName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }
        
		free(tempStrPtr);
		CFRelease(tempCFStringRef);
	}
	else {
		PsychSetStructArrayStringElement("consoleUserName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
	}
	
	tempCFStringRef= SCDynamicStoreCopyLocalHostName(NULL); 
	if (tempCFStringRef) {
		stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingUTF8);
		tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
		stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingUTF8);
        if(stringSuccess) {
            PsychSetStructArrayStringElement("localHostName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("localHostName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }
        
        free(tempStrPtr);        
		CFRelease(tempCFStringRef);
	}
	else {
		PsychSetStructArrayStringElement("localHostName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
	}
	
	tempCFStringRef= SCDynamicStoreCopyLocation(NULL);
	if (tempCFStringRef) {
		stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingUTF8);
		tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
		stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingUTF8);
		if(stringSuccess) {
            PsychSetStructArrayStringElement("location", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("location", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }
		
		free(tempStrPtr);
		CFRelease(tempCFStringRef);
	}
	else {
		PsychSetStructArrayStringElement("location", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
	}

	//Add the ethernet MAC address of the primary ethernet interface to the stuct.  This can serve as a unique identifier for the computer.  
	ethernetMACStrSizeBytes=GetPrimaryEthernetAddressStringLengthBytes(TRUE)+1;
	ethernetMACStr=(char*) malloc(sizeof(char) * ethernetMACStrSizeBytes);
	GetPrimaryEthernetAddressString(ethernetMACStr, TRUE, TRUE);
	PsychSetStructArrayStringElement("MACAddress", 0, ethernetMACStr, majorStruct);
	free(ethernetMACStr);

	//Add the system version string:
	Gestalt(gestaltSystemVersionMajor, &osMajor);
	Gestalt(gestaltSystemVersionMinor, &osMinor);
	Gestalt(gestaltSystemVersionBugFix, &osBugfix);
	
	sprintf(systemVersionStr, "Mac OS %i.%i.%i", osMajor, osMinor, osBugfix);

	//embed it in the return struct
	PsychSetStructArrayStringElement("system", 0, systemVersionStr, majorStruct);

/*
	OLD DEAD Implementation, left for now as a reference...
	//Add the system version string:
	gestaltError=Gestalt(gestaltSystemVersion, &gestaltResult);

	//The result is a four-digit value stored in BCD in the lower 16-bits  of the result.  There are implicit decimal
	// points between the last three digis.  For example Mac OS 10.3.6 is:
	//
	//  0000 0000 0000 0000 0001 0000 0011 0110
	//                         1    0    3    6
	//                         1    0.   3.   6

	strIndex=0;
	//4th digit.
	bcdDigit=gestaltResult & 15;
	gestaltResult= gestaltResult>>4;
	strIndex=strIndex+sprintf(systemVersionStr+strIndex, "%i", bcdDigit);

	//decimal point
	strIndex=strIndex+sprintf(systemVersionStr+strIndex, "%s", ".");

	//3rd digit
	bcdDigit=gestaltResult & 15;
	gestaltResult= gestaltResult>>4;
	strIndex=strIndex+sprintf(systemVersionStr+strIndex, "%i", bcdDigit);

	//decimal point
	strIndex=strIndex+sprintf(systemVersionStr+strIndex, "%s", ".");

	//second digit
	//2nd digit.
	bcdDigit=gestaltResult & 15;
	gestaltResult= gestaltResult>>4;
	strIndex=strIndex+sprintf(systemVersionStr+strIndex, "%i", bcdDigit);

	//1st digit
	bcdDigit=gestaltResult & 15;
	gestaltResult= gestaltResult>>4;
	strIndex=strIndex+sprintf(systemVersionStr+strIndex, "%i", bcdDigit);

	//preface with "Mac OS "  
	strIndex=strIndex+sprintf(systemVersionStr+strIndex, "%s", " SO caM");

	//reverse to make it forward
	lengthSystemVersionString=strlen(systemVersionStr);
	for(i=0;i<lengthSystemVersionString;i++){
		systemVersionStrForward[lengthSystemVersionString-1-i]=systemVersionStr[i];
	}

	systemVersionStrForward[lengthSystemVersionString]='\0';
	//embed it in the return struct
	PsychSetStructArrayStringElement("system", 0, systemVersionStrForward, majorStruct);
*/

    return(PsychError_none);
}
PsychError SCREENComputer(void) 
{
    const char *majorStructFieldNames[]={"macintosh", "windows", "osx" ,"linux", "kern", "hw", "processUserLongName", 
                                         "processUserShortName", "consoleUserName", "machineName", "localHostName", "location", "MACAddress", "system", "gstreamer", "supported" };
    const char *kernStructFieldNames[]={"ostype", "osrelease", "osrevision", "version","hostname"};
    const char *hwStructFieldNames[]={"machine", "model", "ncpu", "physmem", "usermem", "busfreq", "cpufreq"};
    int numMajorStructDimensions=-1, numKernStructDimensions=-1, numHwStructDimensions=-1;
    int numMajorStructFieldNames=16, numKernStructFieldNames=5, numHwStructFieldNames=7;
    PsychGenericScriptType	*kernStruct, *hwStruct, *majorStruct;
    //char tempStr[CTL_MAXNAME];   //this seems like a bug in Darwin, CTL_MAXNAME is shorter than the longest name.  
    char            tempStr[256], *ethernetMACStr;
    size_t          tempIntSize,  tempStrSize, tempULongIntSize;
    int             mib[2];
    int             tempInt;
    psych_uint64    tempULongInt;
    char            *tempStrPtr;
    CFStringRef     tempCFStringRef;
    psych_bool      stringSuccess;
    int             stringLengthChars, ethernetMACStrSizeBytes;
    long            gestaltResult;
    OSErr           gestaltError;
    int             i,strIndex, bcdDigit, lengthSystemVersionString;
    int             osMajor, osMinor, osBugfix;
    char            systemVersionStr[256];

    //all subfunctions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(0));

    //fill the major struct 
    PsychAllocOutStructArray(1, FALSE, numMajorStructDimensions, numMajorStructFieldNames, majorStructFieldNames, &majorStruct);
    PsychSetStructArrayDoubleElement("macintosh", 0, 0, majorStruct);
    PsychSetStructArrayDoubleElement("windows", 0, 0, majorStruct);
    PsychSetStructArrayDoubleElement("linux", 0, 0, majorStruct);
    PsychSetStructArrayDoubleElement("osx", 0, 1, majorStruct);

    // Official support status:
    PsychSetStructArrayStringElement("supported", 0, (char*) PsychSupportStatus(), majorStruct);

    // GStreamer availability and rough version:
    #if defined(PTB_USE_GSTREAMER)
        #if GST_CHECK_VERSION(1,0,0)
        PsychSetStructArrayDoubleElement("gstreamer", 0, 1 * 10000 + 0 * 100 + 0, majorStruct);
        #else
        PsychSetStructArrayDoubleElement("gstreamer", 0, 0 * 10000 + 10 * 100 + 0, majorStruct);
        #endif
    #else
        PsychSetStructArrayDoubleElement("gstreamer", 0, 0, majorStruct);
    #endif

    //fill the kern struct and implant it within the major struct
    PsychAllocOutStructArray(-1, FALSE, numKernStructDimensions, numKernStructFieldNames, kernStructFieldNames, &kernStruct);
    mib[0]=CTL_KERN;

    mib[1]=KERN_OSTYPE;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("ostype", 0, tempStr, kernStruct);

    mib[1]=KERN_OSRELEASE;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("osrelease", 0, tempStr, kernStruct);

    mib[1]=KERN_OSREV;
    tempIntSize=sizeof(tempInt);
    ReportSysctlError(sysctl(mib, 2, &tempInt, &tempIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("osrevision", 0, (double)tempInt, kernStruct);

    mib[1]=KERN_VERSION;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("version", 0, tempStr, kernStruct);

    mib[1]=KERN_HOSTNAME;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("hostname", 0, tempStr, kernStruct);
    PsychSetStructArrayStructElement("kern",0, kernStruct, majorStruct);

    //fill the hw struct and implant it within the major struct
    PsychAllocOutStructArray(-1, FALSE, numHwStructDimensions, numHwStructFieldNames, hwStructFieldNames, &hwStruct);
    mib[0]=CTL_HW;

    mib[1]=HW_MACHINE;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("machine", 0, tempStr, hwStruct);

    mib[1]=HW_MODEL;
    tempStrSize=sizeof(tempStr);
    ReportSysctlError(sysctl(mib, 2, tempStr, &tempStrSize, NULL, 0));
    PsychSetStructArrayStringElement("model", 0, tempStr, hwStruct);

    mib[1]=HW_NCPU;
    tempIntSize=sizeof(tempInt);
    ReportSysctlError(sysctl(mib, 2, &tempInt, &tempIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("ncpu", 0, (double)tempInt, hwStruct);

    mib[1]=HW_MEMSIZE;
    tempULongIntSize=sizeof(tempULongInt);
    tempULongInt = 0;
    ReportSysctlError(sysctl(mib, 2, &tempULongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("physmem", 0, (double)tempULongInt, hwStruct);

    mib[1]=HW_USERMEM;
    tempULongIntSize=sizeof(tempULongInt);
    tempULongInt = 0;
    ReportSysctlError(sysctlbyname("hw.usermem", &tempULongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("usermem", 0, (double)tempULongInt, hwStruct);

    mib[1]=HW_BUS_FREQ;
    tempULongIntSize=sizeof(tempULongInt);
    tempULongInt = 0;
    ReportSysctlError(sysctlbyname("hw.busfrequency", &tempULongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("busfreq", 0, (double)tempULongInt, hwStruct);

    mib[1]=HW_CPU_FREQ;
    tempULongIntSize=sizeof(tempULongInt);
    tempULongInt = 0;
    ReportSysctlError(sysctlbyname("hw.cpufrequency", &tempULongInt, &tempULongIntSize, NULL, 0));
    PsychSetStructArrayDoubleElement("cpufreq", 0, (double)tempULongInt, hwStruct);
    PsychSetStructArrayStructElement("hw",0, hwStruct, majorStruct);

    //fill in the process user, console user and machine name in the root struct.
    tempCFStringRef = SCDynamicStoreCopyComputerName(NULL, NULL);
    if (tempCFStringRef) {
        stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingASCII);
        tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
        stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingASCII);

        if(stringSuccess) {
            PsychSetStructArrayStringElement("machineName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("machineName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }

        free(tempStrPtr);
        CFRelease(tempCFStringRef);
    }
    else {
        PsychSetStructArrayStringElement("machineName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
    }

    struct passwd* thisUser = getpwuid(getuid());
    if (thisUser) {
        PsychSetStructArrayStringElement("processUserShortName", 0, thisUser->pw_name, majorStruct);
    }
    else {
        PsychSetStructArrayStringElement("processUserShortName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
    }

    PsychSetStructArrayStringElement("processUserLongName", 0, PsychCocoaGetFullUsername(), majorStruct);

    tempCFStringRef= SCDynamicStoreCopyConsoleUser(NULL, NULL, NULL);
    if (tempCFStringRef) {
        stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingASCII);
        tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
        stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingASCII);

        if(stringSuccess) {
            PsychSetStructArrayStringElement("consoleUserName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("consoleUserName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }

        free(tempStrPtr);
        CFRelease(tempCFStringRef);
    }
    else {
        PsychSetStructArrayStringElement("consoleUserName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
    }

    tempCFStringRef= SCDynamicStoreCopyLocalHostName(NULL);
    if (tempCFStringRef) {
        stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingASCII);
        tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
        stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingASCII);
        if(stringSuccess) {
            PsychSetStructArrayStringElement("localHostName", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("localHostName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }

        free(tempStrPtr);
        CFRelease(tempCFStringRef);
    }
    else {
        PsychSetStructArrayStringElement("localHostName", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
    }

    tempCFStringRef= SCDynamicStoreCopyLocation(NULL);
    if (tempCFStringRef) {
        stringLengthChars=(int) CFStringGetMaximumSizeForEncoding(CFStringGetLength(tempCFStringRef), kCFStringEncodingASCII);
        tempStrPtr=malloc(sizeof(char) * (stringLengthChars+1));
        stringSuccess= CFStringGetCString(tempCFStringRef, tempStrPtr, stringLengthChars+1, kCFStringEncodingASCII);
        if(stringSuccess) {
            PsychSetStructArrayStringElement("location", 0, tempStrPtr, majorStruct);
        }
        else {
            PsychSetStructArrayStringElement("location", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
        }

        free(tempStrPtr);
        CFRelease(tempCFStringRef);
    }
    else {
        PsychSetStructArrayStringElement("location", 0, "UNKNOWN! QUERY FAILED DUE TO EMPTY OR PROBLEMATIC NAME.", majorStruct);
    }

    //Add the ethernet MAC address of the primary ethernet interface to the stuct.  This can serve as a unique identifier for the computer.
    ethernetMACStrSizeBytes=GetPrimaryEthernetAddressStringLengthBytes(TRUE)+1;
    ethernetMACStr=(char*) malloc(sizeof(char) * ethernetMACStrSizeBytes);
    GetPrimaryEthernetAddressString(ethernetMACStr, TRUE, TRUE);
    PsychSetStructArrayStringElement("MACAddress", 0, ethernetMACStr, majorStruct);
    free(ethernetMACStr);

    //Add the system version string:
    PsychCocoaGetOSXVersion(&osMajor, &osMinor, &osBugfix);
    sprintf(systemVersionStr, "Mac OS %i.%i.%i", osMajor, osMinor, osBugfix);

    //embed it in the return struct
    PsychSetStructArrayStringElement("system", 0, systemVersionStr, majorStruct);

    return(PsychError_none);
}