понедельник, 26 сентября 2011 г.

Немного про sudo

В дефолтных настройках sudo запрашивает пароль того пользователя, который пытается его использовать. В тех случаях, когда нужно разрешить пользователю время от времени получать права суперпользователя, это хорошо. Но что если хочется запускать свои приложения из под другого пользователя чей пароль ты не знаешь. Так, например, приезжая в гости к родителям, хочется запустить свой скайп и копете, при это не перелогиниваясь и не прося сестру ввести её пароль в ответ на требование от kdesudo.

Среди опций файла sudoers имеется targetpw который меняет дефолтное поведение sudo. После чтения его описания впадаешь в уныние, так как сказано, что это глобальный флаг, но покопавшись в разделе examples в man 5 sudoers находим, что глобальные опции тоже можно включать избирательно.
 Defaults targetpw  
 Defaults>root !targetpw  

Позволяет требовать пароль пользователя под которым собираешься исполнить команду либо требовать пароль пользователя который пытается использовать sudo ежели целевой пользователь это root.

четверг, 25 августа 2011 г.

Bash 32bit unsigned dec to hex

Конвертируем десятичные числа в шестнадцатеричные в bash и видим, что числа больше 2 миллиардов становятся отрицательными. Тут нужно немного простой математической магии:
 VAL=3123456789  
 printf "%#x%x" $(( ${VAL} / 65536 )) $(( ${VAL} % 65536 ))   

понедельник, 2 мая 2011 г.

gcc Тёмная магия линкера

Последние пару дней упорно бился над проблемой потерянного символа. Обстоятельства его потери были не столь уж и мистическими, причину я понял сразу. А вот какое заклятье использовать дабы её искоренить, я понял только после детального изучения манов и кучи экспериментов.

Итак имеется статическая библиотека А и несколько плюсовых исходников. Юный маг хочет собрать из этого всего динамическую библиотеку. Разумеется это ему удаётся сделать одной левой, но... В полученной библиотеке отсутствует один из символов имеющихся в скатической библиотеке, который нигде более в рамках имеющегося кода не вызывается.

Ситуация выглядит логично. Просто линкер обнаружил unreferenced symbol и для оптимизации размера сгенерённого файла и ускорения зугрузки библиотеки не стал включать мёртвый код. Ну откуда ему знать, что это точка входа в приложение, которая будет позвана из Java кода через JNI. И собственно потерять можно всё что угодно, но не этот символ.

На помощь пришёл невнятно описанный в манах ключ -u. Он явно говрорит линкеру считать символ имя которого переданно аргументом этому ключу как undefined символ и провести поиск этого символа в библиотеках использумемых при линковке. Это заклинание помогло спасти бедный символ от жестогкого скальпеля линкера.

В процессе исследования было найдено ещё одно интересное чародейство, позволяюще ускорять время загрузки бинамической библиотеки путём исключения из таблицы символов внутренних функций и переменных библиотеки. Если нужно чтобы таблица символов содержала только публичный интерфейс библиотеки, то публичные функции, классы и переменные нужно промаркировать с помощью __attribute__((visibility("default"))):
 __attribute__((visibility("default")))  
 void foo();  
 class __attribute__((visibility("default"))) MyClass {  
 };  
 __attribute__((visibility("default")))  
 int globalNum = 5;  

После чего при компиляции нужно использовать флаг -fvisibility=hidden.

Суть сей магии достаточно проста. По умолчанию gcc считает все символы публичными и при линковке динамической библиотеки перечисляет абсолютно всё в таблице символов. Если что-то или кто-то используется только библиотечными потрохами и наружу смотреть не должно, то его можно явно промаркировать с помощью __attribute__((visibility("hidden"))) и оно не попадёт в таблицу символов. Но, как правило, публичный интерфейс намного меньше приватного и реже меняется, поэтому куда логичней перечислять символы которые должны быть видны. Тут на помощь приходит флаг -fvisibility=hidden который указывает, что все символы, для которых не указанно обратное, нужно считать спрятанными.

Зесь есть абсолютно полная аналогия с подходом в Windows и их __declspec(dllexport). К счастью тут не наблюдается ничего подобного маразматичному __declspec(dllimport). Символ промаркерованный с помощью __attribute__((visibility("default"))) в публичном хедере не нужно маркировать как-то иначе при компиляции приложения использующего данную динамическую библиотеку.