Определение состояния входа в систему пользователя консоли
Q: Как я говорю, зарегистрирован ли в настоящее время пользователь консоли?
A: Как я говорю, зарегистрирован ли в настоящее время пользователь консоли?
Это действительно зависит от того, чем Вы подразумеваете, «в настоящее время входил в систему». С введением быстрого переключения между пользователями в Mac OS X 10.3, в многочисленных пользователей можно войти система одновременно. Так, необходимо разделить вопрос в два:
Как я получаю список сеансов входа в систему GUI?
Какой сеанс входа в систему GUI, если таковые имеются, в настоящее время использует консоль?
Это ясные вопросы с ясными ответами (см. ниже). Однако вероятно, что, если Вы задаете эти вопросы, необходимо заново продумать архитектуру.
Один из фундаментальных принципов разработки Mac OS X - то, что высокоуровневые службы могут зависеть от низкоуровневых служб, но не наоборот. Например, для приложения хорошо зависеть от ядра, но это - проблема, если ядро зависит от приложения.
Вопрос определения текущего пользователя консоли обычно возникает при повреждении этого принципа разработки. Только службы прикладного уровня должны заботиться, в настоящее время активен ли сеанс пользователя на консоли, и для таких служб просто определить это. С другой стороны, демон не должен быть обеспокоен тем, зарегистрирован ли пользователь на консоли, и таким образом это хитро для получения этой информации от того контекста.
Этот вопрос обсужден в большой глубине в Техническом примечании TN2083, 'Демоны и Агенты' и, в частности, в разделе «Design Considerations» этого technote. Так, перед чтением остальной части этого документа я строго рекомендую считать, что technote и думают о том, как можно выровнять архитектуру с полной архитектурой Mac OS X.
Это предполагает, что компьютер имеет единственную консоль GUI. В то время как это правда в настоящее время, это может не быть истина навсегда. Если эта ситуация изменяется, при использовании этого метода, необходимо будет изменить код.
Это не имеет никакого способа указать, что зарегистрированы многочисленные пользователи.
Это не имеет никакого способа указать, что пользователь зарегистрирован, но переключился на окно входа в систему.
Из-за этих проблем, подпрограмм как SCDynamicStoreCopyConsoleUser существуйте только в целях совместимости. Вероятно, что они будут формально осуждаться в будущей версии Mac OS X.
Если Вы принимаете решение проигнорировать все предупреждения выше, вот ответы на Ваши вопросы:
Как я получаю список сеансов входа в систему GUI? — В Mac OS X 10.5 и позже можно использовать utmpx API для получения этой информации. Для примера этого посмотрите Пример кода 'UTXplorer'.
До Mac OS X 10.5 не было никакого поддерживаемого способа получить эту информацию непосредственно. Техническое примечание TN2083, 'Демоны и Агенты' предлагают косвенный способ сделать это, базировало центрального демона с рядом сотрудничающих агентов. Этот проект будет работать над всеми версиями Mac OS X и обычно выровненный полного принципа разработки Mac OS X, описанного ранее.
Какой сеанс входа в систему GUI, если таковые имеются, в настоящее время использует консоль? — Этому отвечают ниже.
Можно получить имя пользователя текущего пользователя консоли путем вызова SCDynamicStoreCopyConsoleUser функция (от платформы Конфигурации системы). Перечисление 1 показывает, как сделать это.
Перечисление 1 , Получающее текущего пользователя консоли
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;
} |
Когда эта установка изменяется, платформа Конфигурации системы также упрощает быть уведомленной. Перечисление 2 показывает, как сделать это.
Перечисление 2 , Обнаруживающее, когда изменяется та установка
#include <assert.h>
#include <SystemConfiguration/SystemConfiguration.h>
static CFStringRef CopyCurrentConsoleUsername(SCDynamicStoreRef store);
// defined above
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;
} |
История версии документа
| Дата | Примечания |
|---|---|
| 14.04.2008 | Полная перезапись, чтобы составить быстрое переключение между пользователями и упростить код. |
| 08.04.2002 | Новый документ, что, как определить, зарегистрирован ли пользователь на консоли, и быть уведомленным относительно изменений. |