ESO Midas 11SEP1.2

Отправил собираться новую версию.

Заодно осилил source service для build service. Первый приз получает сервис под названием download_files (надо в файл _service в проекте воткнуть вот это):
<services>
  <service name="download_files">
  <param name="recompress">yes</param>
  </service>
</services>

Он не просто прочитает spec-файл и попытается скачать все файлы для которых там есть полный url в строчке Source, он к тому-же (это же чудо!) перепакует их сам в нужный формат и сам разберется что скачивать. Например, допустим, Source0 указан вот так: ftp://ftp.eso.org/pub/midaspub/11SEP/sources/%{version}.tar.bz2, при этом на самом сервере нет архива tar.bz2, там есть только tar.gz. Так вот, умный сервис скачает такой архив, который там физически есть, и перепакует его в такой, который нужен.

Документации (как и во всем opensuse) нет, поэтому предлагается смотреть в /usr/lib/obs/service и там можно прочитать в исходниках какие сервисы есть, какие у них параметры и что делают.

p.s. Вообще, считаю, следующий гениальный шаг будет когда build service научится сам автоматически отслеживать хранилища типа PyPi, CPAN, etc и автоматом собирать новые пакеты и пересобирать обновленные. Закоммитил ты свой модуль новый питонный в PyPi, а он через 15 минут уже есть для opensuse в виде пакета. Красота.

PAM и ssh-agent

Захотелось, чтобы можно было входить в систему, используя пароль от ssh-ключа, и при этом чтобы ssh-agent запускался и больше пароль никогда не спрашивал. Все это можно сделать используя модуль pam_ssh для PAM (Pluggable Authentication Modules for Linux).

Настроить его очень просто: надо воткнуть в auth
auth    sufficient      pam_ssh.so
а в session, соответственно
session sufficient      pam_ssh.so

В PAM модули работают как и везде: динамически загружается .so-файл, и запускаются у него функции с наперед известными именами, куда передаются разные параметры, с которыми модуль знает что делать. Первая строчка, таким образом, ответственна за проверку пароля к ssh-ключу, вторая строчка — запуск правильного процесса ssh-agent.

Запуская ssh-agent, pam_ssh.so делает в ~/.ssh файл с именем в духе agent-$HOSTNAME и содержанием вида:
SSH_AUTH_SOCK=/tmp/ssh-qjtjCQkp2852/agent.2852; export SSH_AUTH_SOCK;
SSH_AGENT_PID=2853; export SSH_AGENT_PID;
echo Agent pid 2853;

Вообще говоря, после этого можно в .profile или .bashrc просто выполнить этот файл как кусок скрипта. После этого нужные переменные среды окружения будут иметь нужные значения и ssh правильно подцепит свой агент. Однако, в PAM предусмотрен модуль pam_env ответственный за установку переменных среды окружения. Автоматом почему-то ничего не заработало, но заработало после добавления в /etc/security/pam_env.conf строчек:
SSH_AUTH_SOCK DEFAULT="" OVERRIDE=@{SSH_AUTH_SOCK}
SSH_AGENT_PID DEFAULT="" OVERRIDE=@{SSH_AGENT_PID}

GNU R: график плотности числа точек

Иногда бывает нужно построить то, что называется диаграммой рассеяния (scatter-plot). Когда число точек на графике превышает некоторый предел, график становится почти бесполезен потому-что на нем появляется гигантская клякса (это точки (или другие символы, которые изображаются) многократно налезают друг на друга). В таких случаях предлагается строить график плотности числа точек. Сначала нужно вычислить её (хоть каким-нибудь образом), в GNU R для этого предусмотрена функция kde2d из пакета MASS. Потом полученный объект можно рисовать через contour.

Пример который рисует отличную разноцветную диаграмму:

density <- kde2d(x1,x2,lims=c(lower1,upper1,lower2,upper2))
mycol <- function(n) gray((n+1):0/(n+1))
filled.contour(density,color.palette=mycol)
filled.contour понимает title и все остальное.

smtp_bind_address

Параметр smtp_bind_address для postfix позволяет привязать ip-адрес для соединений. Бывает полезно, когда на одном интерфейсе привязано несколько(много) ip-адресов, при этом одинаково доступный relayhost предпочитает один определенный (либо явно, либо по причине что один из адресов не резолвится в обе стороны).

udev и video4linux

Оказывается, /lib/udev/rules.d/60-persistent-v4l.rules делает символические ссылки на устройства video4linux (/dev/videoN): /dev/v4l/by-id и /dev/v4l/by-path.

Очень удобно оказалось использовать, например, /dev/v4l/by-id/usb-0471_0329_01690000A6480288-video-index0 вместо /dev/video0 (или /dev/video1), когда камер много.

v4l (video for linux) 1.0

Это пост для миграции с первой версии v4l API на v4l2.

Если правильно понимаю, поддержка первой версии была окончательно удалена этим коммитом. Где-то между ядром 2.6.36 и 2.6.37.

dhcp клиенты

В openSUSE 11.4 оказалось два dhcp-клиента: dhclient (авторства ISC из пакета dhcp-client) и dhcpcd (почему-то версии 3.2.3 авторства авторов dhcpcd из одноименного пакета). Кстати, последний наотрез отказался удаляться, объясняя это тем, что пакет с mkinitrd от него зависит.

Переключаются они между собой в файле /etc/sysconfig/network/dhcp, там есть соответствующая переменная DHCLIENT_BIN.

p.s. А все это для чего. Утром словил с dhcpcd вот это:

wlan0: offered 192.168.1.1 from 192.168.0.1 `host.local'
wlan0: got subsequent offer of 192.168.1.2, ignoring 
wlan0: checking 192.168.1.1 is available on attached networks
wlan0: ARPOP_REPLY received from 192.168.1.1 (00:12:34:56:78:9a)

И пришлось использовать dhcp-клиент, который сделал мне хорошо.

Драйвер базы данных для Akonadi

Выяснилось, что тот самый Akonadi запускает сервер MySQL для собственного существования. Разработчики на этот счет пишут, что ничего лучше не может быть, они честно пробовали SQLite, но он плохо у них справляется с одновременными запросами.

Однако есть способ открутить его оттуда. В файле ~/.config/akonadi/akonadiserverrc есть строчка Driver в секции General, туда подходят следующие значения (не все из них могут быть включены при компиляции):

  • QMYSQL, QMYSQL_EMBEDDED (Mysql)
  • QSQLITE, QSQLITE3 (SqLite)
  • QPSQL (Postgresql)
  • QODBC (Virtuoso)

Вполне богатый выбор.

GPS как источник точного времени в NTP

Драйвер приемника, передающего данные по стандарту NMEA, живет по адресу 127.127.20.x (в этом случае читать его ntpd будет из /dev/gpsx). Нужно позаботиться о наличии символической ссылки на соответствующее устройство: /dev/ttySx (для работы через последовательный порт), /dev/ttyUSBx (для подключения через USB), или /dev/rfcommx (для работы через rfcomm).

Далее надо сделать доступным для ntpd это устройство: проследить, что оно создается в chroot, если ntpd запускается там, установлены ли правильные права доступа, нет ли ограничений на доступ для процесса ntpd в профилях AppArmor или SELinux.

После этого, нужно добавить в конфигурационный файл server 127.127.20.0. Это некоторая форма записи желания работать с драйвером Generic NMEA GPS. Полный список доступных драйверов находится здесь. Они все настраиваются аналогичным образом.

При удачном старте ntpd сообщит в логах примерно следующее:
22 Jun 14:13:15 ntpd[2165]: GPS_NMEA(0) serial /dev/gps0 open at 4800 bps

При этом ntp -np сообщит что-то вроде этого:
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*127.127.20.0    .GPS.            0 l   11   64   77    0.000  -99.226  59.612
 127.127.1.0     .LOCL.          10 l    -   64    0    0.000    0.000   0.000

Meade RCX(LX)-400

Изумленная публика сегодня обнаружила незаурядное техническое решение компании Meade. Внутри LX-400 есть две платы: одна с контроллером, вторая с неким подобием USB-хаба. На первой из них расположен разъем USB-B, который просто распаян на внутренний коннектор, с которого уходит шлейф на вторую плату. Оттуда по другому шлейфу он возвращается на второй коннектор и только после этого что-то уходит на контроллер.

Осмыслить это дело удалось, но факт в том, что одну снятую плату просто так не получилось перепрошить в защищенной моде программой производителя, потому-что компьютер через USB подключается к воздуху, а не к контроллеру.

Обновление на openSUSE 11.4

Обновляюсь с openSUSE 11.3 на openSUSE 11.4. zypper dup сначала радостно снес у меня пакет liblzma0-4.999.9beta, а через мгновение rpm выяснил, что не может почему-то запуститься без lzma0, жалобно смотрел на меня и говорил:
rpm: error while loading shared libraries: liblzma.so.0: cannot open shared object file: No such file or directory
Тут все бы и закончилось, если бы я не скачал и не подсунул нужную библиотеку ему.

upd: тут в комментариях умные люди сделали правильные оргвыводы. zypper addlock liblzma0, либо обновляться с http-репозитория, а не с DVD.

openSUSE Build Service: kvm с поддержкой virtio

Инструкция по созданию образа initrd с поддержкой virtio. В файле
/etc/sysconfig/obs-worker должно быть указано, где какие образы искать рабочим(а то сами они могут не то найти), кроме того, там указана файловая система, которую вы желаете использовать для виртуальных дисков (у меня по умолчанию был ext3). По идее, файловая система важна только чтобы initrd смог потом её смонтировать.

rootfstype="ext4" mkinitrd -d /dev/null -m "binfmt_misc virtio_pci virtio_blk" -k /boot/vmlinuz -i /boot/initrd-virtio -S

Создаст специальный initrd, который потом можно скормить сборщикам. Важно указать rootfstype, иначе mkinitrd начинает пытаться определить тип файловой системы у /dev/null и ругается.

upd: В скором времени восприятие /dev/null было окончательно починено (поломано). Несмотря на то, что скрипт build до сих пор содержит напоминание о ключе -d /dev/null, эта опция больше не работает. Самым простым способом оказалось копирование /lib/mkinitrd куда-нибудь в сторону и наглое исправление файла scripts/setup-storage.sh:
@@ -331,9 +331,10 @@
             fstype=nfs
             ;;
         /dev/*)
-            if [ ! -e "$dev" ]; then
-                error 1 "$name device ($dev) not found"
-            fi
+       fstype=$rootfstype
             ;;
         *://*) # URL type
             fstype=${dev%%://*}

После чего следует использовать команду:

rootfstype="ext4" mkinitrd -d /dev/vda -m "binfmt_misc virtio_pci virtio_blk" -k /boot/vmlinuz -i /boot/initrd-virtio -S -l /path/to/lib/mkinitrd

VirtualBox 4.0 USB

С выпуском четвертой версии виртуальной машины VirtualBox среди прочих изменений в стала доступна возможность подключения USB-устройств в гостевой ОС. Вообще говоря, такая возможность была раньше и в проприетарной версии.

При попытке воспользоваться этой возможностью может обнаружиться примерно такой симптом: в списке устройств все устройства подключенные к физической машине есть, но они "неактивные" и галочки не горят. Соответственно, в гостевой ОС их не видно.

Существуют инструкции, в том числе и на официальном сайте VirtualBox, где объясняется как монтировать /proc/bus/usb, чтобы все заработало. Так вот, эта инструкция только для относительно старых ядер, например в openSUSE 11.2 монтировать ничего не нужно.

Для активации поддержки USB следует: во-первых, убедиться что существует группа vboxusers и нужные пользователи включены в неё, во-вторых, открыть /etc/udev/rules.d/60-vboxdrv.rules и активировать там соответствующие настройки:

KERNEL=="vboxdrv", NAME="vboxdrv", OWNER="root", GROUP="root", MODE="0600"
#these two lines give access permission to vboxusers to properly work with usb nodes, this could be security risk (bnc#664520) !!
SUBSYSTEM=="usb_device", ATTR{devnum}=="?*", ATTR{busnum}=="?*",NAME="vboxusb/$attr{busnum}/$attr{devnum}", GROUP="vboxusers"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{devnum}=="?*", ATTR{busnum}=="?*",NAME="vboxusb/$attr{busnum}/$attr{devnum}", GROUP="vboxusers"

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

python и ленивые(lazy) атрибуты

В интернете куча примеров как сделать ленивые атрибуты для класса, чтобы не искать, оставлю здесь еще один пример:

class lazy(object):
        def __init__(self, function):
                self._function = function

        def __get__(self, instance, owner = None):
                if instance == None:
                        return self
                val = self._function(instance)
                setattr(instance, self._function.func_name, val)
                return val

class line(object):
        def __init__(self, line = None):
                self._line = line

        @lazy
        def items(self):
                return self._line.split()

Объяснение: items, коль скоро он декорируется, становится объектом класса lazy, и начинает восприниматься как дескриптор(descriptor). Поэтому __get__, __set__ и __delete__ могут быть определены у класса lazy. Конкретная реализация __get__ вычисляет значение функции и привязывает объект с результатом в качестве атрибута вместо себя на свое имя. Значит, последующие обращения к items — уже не вызов функции, а просто операции со списком, что вернулся при первом вызове.

boost.python

Для сборки чего-либо с использованием boost.python его авторы рекомендуют использовать bjam, угрожая при этом в документации, что если что-то и отвалится, то исключительно по причине не использования оного.

Если не использовать bjam, то существует подсказка для выбора правильных параметров для компиляции и линковки: идем в ./libs/python/example/quickstart и просим bjam -n (т.е. распечатать команды вместо того, чтобы их запускать)

Кроме того, у меня работал вот такой Makefile:
all: test1.so

test1.so: test1.o
 $(CXX) -shared $< -o $@ -lboost_python

test1.o: test1.cpp
 $(CXX) `python-config --includes` -fPIC $< -c -o $@