Last active
July 18, 2022 19:05
-
-
Save t0rr3sp3dr0/3f8b843c3cc2d356eb34a59a2d192af3 to your computer and use it in GitHub Desktop.
https://developer.apple.com/library/archive/qa/qa1133/_index.html clang -framework CoreFoundation -framework SystemConfiguration ./console_user.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <SystemConfiguration/SystemConfiguration.h> | |
static CFStringRef CopyCurrentConsoleUsername(SCDynamicStoreRef store) | |
// Returns the name of the current console user, or NULL if there is | |
// none. store may be NULL, in which case a transient dynamic store | |
// session is used. | |
{ | |
CFStringRef result; | |
result = SCDynamicStoreCopyConsoleUser(store, NULL, NULL); | |
// If the current console user is "loginwindow", treat that as equivalent | |
// to none. | |
if ( (result != NULL) && CFEqual(result, CFSTR("loginwindow")) ) { | |
CFRelease(result); | |
result = NULL; | |
} | |
return result; | |
} | |
static CFStringRef gCurrentConsoleUser; | |
static void MyNotificationProc( | |
SCDynamicStoreRef store, | |
CFArrayRef changedKeys, | |
void * info | |
) | |
// Called out of our runloop when the current console user value | |
// changes in the dynamic store. It's possible to get multiple | |
// redundant notifications, so we debounce the notification by checking | |
// for changes relative to gCurrentConsoleUser. | |
{ | |
#pragma unused(changedKeys) | |
#pragma unused(info) | |
CFStringRef currentConsoleUser; | |
Boolean didChange; | |
// Get the current console user. | |
currentConsoleUser = CopyCurrentConsoleUsername(store); | |
// See if it changed. | |
didChange = (gCurrentConsoleUser != NULL) != (currentConsoleUser != NULL); | |
if ( ! didChange && (gCurrentConsoleUser != NULL) ) { | |
assert(currentConsoleUser != NULL); // because if it was NULL, | |
// didChange would already be true | |
didChange = ! CFEqual(gCurrentConsoleUser, currentConsoleUser); | |
} | |
// If it did, log that fact and remember the current value. | |
if (didChange) { | |
if (gCurrentConsoleUser != NULL) { | |
CFRelease(gCurrentConsoleUser); | |
} | |
gCurrentConsoleUser = currentConsoleUser; | |
if (gCurrentConsoleUser != NULL) { | |
CFRetain(gCurrentConsoleUser); | |
} | |
CFShow(gCurrentConsoleUser); | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
#pragma unused(argc) | |
#pragma unused(argv) | |
Boolean success; | |
SCDynamicStoreRef store; | |
CFStringRef key; | |
CFArrayRef keys; | |
CFRunLoopSourceRef rls; | |
// Set up our connection to the dynamic store so that notifications are | |
// delivered by calling MyNotificationProc. | |
store = SCDynamicStoreCreate( | |
NULL, | |
CFSTR("com.apple.dts.ConsoleUser"), | |
MyNotificationProc, | |
NULL | |
); | |
assert(store != NULL); | |
// Set it up to notify us when the console user value changes. | |
key = SCDynamicStoreKeyCreateConsoleUser(NULL); | |
assert(key != NULL); | |
keys = CFArrayCreate(NULL, (const void **) &key, 1, &kCFTypeArrayCallBacks); | |
assert(keys != NULL); | |
success = SCDynamicStoreSetNotificationKeys(store, keys, NULL); | |
assert(success); | |
// Add it to the runloop. | |
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0); | |
assert(rls != NULL); | |
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); | |
// Print the current value. | |
gCurrentConsoleUser = CopyCurrentConsoleUsername(store); | |
CFShow(gCurrentConsoleUser); | |
// Run forever printing any changes. | |
CFRunLoopRun(); | |
// Clean up code. This simple tool will never execute this code | |
// (because CFRunLoopRun will never return), but I've left it here | |
// in case you adapt the code for a more complex situation. | |
if (gCurrentConsoleUser != NULL) { | |
CFRelease(gCurrentConsoleUser); | |
} | |
CFRunLoopSourceInvalidate(rls); | |
CFRelease(rls); | |
CFRelease(keys); | |
CFRelease(key); | |
CFRelease(store); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment