Прямо сейчас gphoto поддерживает 1598 моделей камер и список постоянно растет. Проект собирается под все UNIX-like ОС, включая Linux и Mac OS X. Съемкой можно управлять как при помощи command line утилиты, так и из своей собственной программы, используя библиотеку libgphoto. Доступны биндинги для разных языковых платформ, включая node.js.
В современных ОС присутствуют встроенные средства для работы с цифровыми камерами — как правило под «работой» подразумевается только выгрузка фото из камеры. Эти встроенные механизмы препятствуют работе gphoto, так как захватывают USB устройство в эксклюзивном режиме. Особенно интересно дела в этом плане обстоят в Mac OS X — ОС не предоставляет никаких штатных возможностей для отключения, но при этом система поддержки цифровых камер легко поддается реверс инжинирингу.
Скрипты для блокировки запуска PTPCamera на github.
PTPCamera
Интернет советует выполнить команду killall -9 PTPCamera
(убить процесс PTPCamera) после подключение фотоаппарата для нормальной работы gphoto. Это в самом деле помогает, однако каждый раз при подключении камеры процедуру приходится повторять заново. Разумеется, программу PTPCamera можно просто удалить, но мне хотелось обойтись менее радикальным решением.
В общем, требовалось понять механизм запуска PTPCamera, и максимально корректно отключить эту функцию.
О захвате изображений в Mac OS X
Согласно имеющимся источникам [1,2], инфраструктура захвата изображений в Mac OS X устроена следующим образом.
На вершине стека расположены приложения, с которыми непосредственно взаимодействует пользователь (ex: iPhoto).
В самом низу расположены приложения для управления устройствами, к числу последних относится PTPCamera. Приложения для управления устройствами (MassStorageCamera.app
, PTPCamera.app
, TWAINBridge.app
и тд.) живут в системных папках /System/Library/Image Capture/Devices
и /Library/Image Capture/Devices
.
Посередине находится коммуникационный слой, который организует связь между верхним и нижним уровнями. Любопытно, что несколько пользовательских приложений могут использовать одно устройство совместно, а также возможна прозрачная работа с устройствами по локальной сети.
Кто же запускает PTPCamera?
Попробуем определить механизм запуска PTPCamera, и для начала определим родительский процесс.
$ pgrep PTPCamera 29045 $ ps -O ppid -p 29045 PID PPID TT STAT TIME COMMAND 29045 202 ?? S 0:00.10 /System/Library/Image Capture/Devices/PTPCamer $ ps -p 202 PID TTY TIME CMD 202 ?? 0:16.75 /sbin/launchd
Итак, мы видим что PTPCamera запущен процессом launchd. В Mac OS X launchd — это универсальная запускалка для системных и пользовательских демонов. В системе запущено по экземпляру launchd для каждого активного пользователя. Launchd пользователя root выполняет те же функции, что init в традиционных UNIX системах.
$ ps -A -O user | grep /sbin/launchd 1 root ?? Ss 3:06.80 /sbin/launchd 172 _windowserver ?? Ss 0:00.06 /sbin/launchd 202 nickz ?? Ss 0:16.76 /sbin/launchd 206 _spotlight ?? Ss 0:00.27 /sbin/launchd 28919 _cvmsroot ?? Ss 0:00.01 /sbin/launchd 28937 _securityagent ?? Ss 0:00.01 /sbin/launchd
Кроме демонов, laucnhd также запускает графические приложения по команде других программ. PTPCamera — это именно последний случай, как можно убедиться по ID задачи в launchd, об этом нам говорит [префикс].
$ launchctl list | grep PTPCamera 29045 - [0x0-0x457457].com.apple.PTPCamera
Итак, мы знаем что PTPCamera был запущен процессом launchd, по команде некого приложения X.
Включим логирование launchd (launchctl log level debug
), и спровоцируем повторный запуск PTPCamera.
По умолчанию, на каждый процесс в системе выделена квота в 500 записей в логе в секунду. Сообщения, не уложившиеся в лимит, отбрасываются. Настроим отдельную сборку отладочных сообщений для обхода лимита.
Добавляем в файл /etc/syslog.conf
строку
*.debug /var/log/debug.log
и информируем демон syslogd
о необходимости перечитать настройки
sudo killall -HUP syslogd
Анализируем полученный файл debug.log
. Находим искомое:
([0x0-0x2d92d9].com.apple.PTPCamera[24472]): Spawned by PID 240: com.apple.SystemUIServer.agent
Запрашиваем у launchd
информацию о com.apple.SystemUIServer.agent
:
$ launchctl list com.apple.SystemUIServer.agent { "Program" = "/System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer"; };
Теперь мы знаем, что «виновник» запуска PTPCamera
— это SystemUIServer
, ни много ни мало.
Ковыряем SystemUIServer
Имеется подозрение, что искомый функционал находится не в самом SystemUIServer
, а в одном из прилинкованных фреймворков:
$ otool -L /System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer /System/Library/CoreServices/SystemUIServer.app/Contents/MacOS/SystemUIServer: /System/Library/PrivateFrameworks/CoreUI.framework/Versions/A/CoreUI /System/Library/PrivateFrameworks/Admin.framework/Versions/A/Admin /System/Library/Frameworks/Carbon.framework/Versions/A/Carbon /System/Library/PrivateFrameworks/SystemUIPlugin.framework/Versions/A/SystemUIPlugin /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit /System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit /System/Library/Frameworks/Security.framework/Versions/A/Security /System/Library/PrivateFrameworks/ICANotifications.framework/Versions/A/ICANotifications /System/Library/PrivateFrameworks/iPod.framework/Versions/A/iPod ...
В этом списке главный подозреваемый — ICANotifications.framework
. ICA
— это сокращение от image capture, тот же акроним используется в публичных фреймворках для захвата изображений.
Изучаем ICANotifications.framework
Лирическое отступление. Исполняемый файл состоит из кода и неизменяемых статических данных (разные константы, таблицы, и тп.) Особый интерес представляют строковые константы. Извлечь их можно при помощи команды strings
.
Запускаем strings /System/Library/PrivateFrameworks/ICANotifications.framework/Versions/A/ICANotifications
, и наслаждаемся результатами:
... /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.%d ... CREATE TABLE DBVersion (ID integer primary key not null, typeID integer, value integer) CREATE TABLE SourceFile (ID integer primary key not null, typeID integer, bundleID varchar(256), bundleVersion integer, bundlePath varchar(256), deviceDiscoveryPath varchar(256), deviceDiscoveryModDate varchar(20), readDate varchar(20), iTWAINDS integer) CREATE TABLE IOUSBDevice (ID integer primary key not null, typeID integer, idVendor integer, idProduct integer) CREATE TABLE IOUSBInterface (ID integer primary key not null, typeID integer, bInterfaceClass integer, bInterfaceSubClass integer, bInterfaceProtocol integer) ...
Дык это ж SQL!
Итак, рабочая гипотеза — библиотека работает с SQLite базой данных, наиболее вероятно, что это файл com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase
в /Library/Caches
.
$ ls /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.* /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.501 $ sqlite3 /Library/Caches/com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.501 sqlite> .schema CREATE TABLE DBVersion (ID integer primary key not null, typeID integer, value integer); CREATE TABLE IOUSBDevice (ID integer primary key not null, typeID integer, idVendor integer, idProduct integer); CREATE TABLE IOUSBInterface (ID integer primary key not null, typeID integer, bInterfaceClass integer, bInterfaceSubClass integer, bInterfaceProtocol integer); ...
Так и есть!
Видно, что в конец имени (com.apple.ImageCaptureNotifications.DeviceDiscoveryDatabase.501
) дописывается ID пользователя, для каждого пользователя поддерживается собственный файл. Из содержимого понятно, что база задает список соответствий класса устройств и управляющей программы, которую нужно запускать при обнаружении устройства.
Редактирую базу данных, мы отключаем запуск PTPCamera
для любого выбранного пользователя, это однозначный успех!
При необходимости вернуть все обратно, откатываем изменения, или просто удаляем файл бд (название папки /Library/Caches
сообщает нам, что ОС при необходимости может перегенерировать содержимое).
Дальнейшее — дело техники.
Факультативные материалы
ссылка на оригинал статьи http://habrahabr.ru/post/173323/
Добавить комментарий