2008-12-27

Да будет сканер, в Linux

Несколько месяцев назад я занялся порочной практикой - самостоятельной сборкой ядер Linux. Процесс сам по себе не такой уж и сложный, но я, как человек разумный, решил переделать конфигурацию на свой лад, т.е. убрать всё лишнее, всё что не используется на моей домашней (по совместительству рабочей) машине. Тут и начались проблемы, перестало работать то одно устройство, то другое. Приходилось анализировать исходный конфиг (.config, хватило ума не удалять его, как и предыдущее рабочее ядро) со своим.
Вчера потребовался сканер (USB, Epson Perfection 2480 Photo). Боялся что ничего не заработает на моей сборке ядра и, разумеется, так и получилось. Перезагрузил старое ("оригинальное", из коробки Debian Etch, 2.6.18) ядро, всё нормально. Начал искать в чем причина.
$ sane-find-scanner
found USB scanner (vendor=0x04b8, product=0x0121) at libusb:003:002
Т.е. сканер есть, но его нет:
$ scanimage -L
device `v4l:/dev/video0' is a Noname BT878 video (AVerMedia TVPhone virtual device
То же самое, но под root:
$ sudo scanimage -L
Password:
device `v4l:/dev/video0' is a Noname BT878 video (AVerMedia TVPhone virtual device
device `snapscan:libusb:003:002' is a EPSON EPSON Scanner1 flatbed scanner

Вся закавыка заключается в том, что в своей компиляции я убрал устаревшую (DEPRECATED) опцию USB_DEVICE_CLASS. Если посмотреть описание этой опции, а еще ветку libsane udev rules for 2.6.22 в рассылке sane-devel, то становится ясно в чем дело и как поступить. Идем в /etc/udev/rules.d/z60_libsane.rules (в вашей системе, z60_libsane.rules может иметь другой префикс, не z60_). В начале этого файла должны быть строки:
ACTION!="add", GOTO="libsane_rules_end"                                                                                 
ENV{DEVTYPE}=="usb_device", GOTO="libsane_create_usb_dev"
SUBSYSTEM=="usb_device", GOTO="libsane_rules_begin"
SUBSYSTEM!="usb_device", GOTO="libsane_rules_end"

# Kernel >= 2.6.22 jumps here
LABEL="libsane_create_usb_dev"

# For Linux >= 2.6.22 without CONFIG_USB_DEVICE_CLASS=y
# If the following rule does not exist on your system yet, uncomment it
# ENV{DEVTYPE}=="usb_device", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0664", OWNER="root", GROUP="root"

# Kernel < 2.6.22 jumps here
LABEL="libsane_rules_begin"
Нас интересует строка "If the following rule does not exist on your system yet, uncomment it". Как определить, что такого правила в системе еще нет. Во первых, сканер у нас под обычным пользователем всё еще не работает :-). Во вторых, анализируем выход такой команды:
$ grep -ir 'env{devtype}=="usb_device"' /etc/udev/rules.d/
/etc/udev/rules.d/z60_libsane.rules:ENV{DEVTYPE}=="usb_device", GOTO="libsane_create_usb_dev"
/etc/udev/rules.d/z60_libsane.rules:# ENV{DEVTYPE}=="usb_device", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0664", OWNER="root", GROUP="root"
/etc/udev/rules.d/z60_libsane-extras.rules:ENV{DEVTYPE}=="usb_device", GOTO="libsane_extras_create_usb_dev"
/etc/udev/rules.d/z60_libsane-extras.rules:# ENV{DEVTYPE}=="usb_device", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0664", OWNER="root", GROUP="root"
Очевидно, что такого правила нигде больше нет. Снимаем коментарий с известной строки, перезагружаем систему и радуемся, радуемся я сказал :-). У меня всё заработало:
$ scanimage -L
device `v4l:/dev/video0' is a Noname BT878 video (AVerMedia TVPhone virtual device
device `snapscan:libusb:003:002' is a EPSON EPSON Scanner1 flatbed scanner

2008-10-16

Тормозим оптический привод

Надоел шум нового супер-быстрого CD-ROM (DVD-ROM или пишущего комбайна) при просмотре фильма? Ограничиваем его скорость самым простым способом, который может прийти в голову:
$ eject -x8 /media/cdrom0
Где -x8 — скорость работы привода (при x32 мой привод шумит значительно меньше, почти не заметно, а при x16 его не слышно вообще, вы можете попробовать другие скорости), дальше — точка монтирования вашего устройства, либо это само устройство (/dev/hdc). Я пробовал работать только с точкой монтирования, хотя уверен, что и ссылка непосредственно на устройство, должна сработать. В любом случае, вам поможет гугль и:
$ man eject
Если я всё правильно помню, то первая скорость (CD-ROM Mode 1) это 150 килобайт/сек., т.е. 150 килобайт * 8 бит = 1.2 мегабита. Качество традиционных фильмов MPEG4 колеблется в пределах 700 килобит/сек. + звук, редко больше 128 килобит/сек. итого у нас выходит 828 килобит. Согласитесь, даже для первой скорости, запас очень не плохой. Вывод такой что вы можете не париться и ставить первую или вторую скорость, врядли какой-либо привод будет шуметь на такой скорости, а если диск не испорчен, вы посмотрите его нормально. Да и в повседневной жизни скорость можно уменьшать. Уверен что не всегда нужны обороты в x48 или больше, ведь основной проблемой будут не обороты диска, а перемещение головки — скорость вращения диска дает преимущества только при его последовательном чтении. В сети вы можете найти описание другого утиля для управление скоростью привода, но ни один из них, как и этот способ, не работают при использовании DVD-диска, не знаю в чем дело, но DVD, что очевидно, вращаются с максимальной скоростью и продолжают шуметь, что бы вы не делали.

p.s. Забыл сказать, что речь идет о Linux :-).

2008-10-10

Twisted-клиент и веб-прокси

Как это не парадоксально, но Twisted в своем арсенале не имеет средств для работы с HTTP через прокси-сервер. Я наклепал небольшой код, который решает эту проблему. Сделано не бог весть как, но если кому-то очень нужно, то сгодится и этот код.
from twisted.web import client as _twc


class HTTPPageGetter(_twc.HTTPPageGetter):

def sendCommand(self, command, path):
if self.factory.proxy:
from twisted.web.http import urlparse
from urlparse import urlunparse

domain = urlparse(self.factory.url)[:2]
path = urlparse(path)[2:]
path = urlunparse(domain + path)

self.transport.write('%s %s HTTP/1.0\r\n'%(command, path))

def handleStatus_301(self):
location = self.headers.get('location')
if not location:
self.handleStatusDefault()
return
url = location[0]

if self.followRedirect:
self.factory.connect(url)

else:
from twisted.python.failure import Failure
from twisted.web.error import PageRedirect

self.handleStatusDefault()
self.factory.noPage(Failure(
PageRedirect(self.status, self.message,
location = url)))

self.quietLoss = 1
self.transport.loseConnection()



class HTTPClientFactory(_twc.HTTPClientFactory):

protocol = HTTPPageGetter
proxy = None

def __init__(self, url, **kwargs):
self.proxy = kwargs.pop('proxy', None)
_twc.HTTPClientFactory.__init__(self, url, **kwargs)

def connect(self, url = None):
if url:
self.setURL(url)

if self.proxy is not None:
try:
host, port = self.proxy.split(':')
host, port = str(host), int(port)
except:
raise Exception(
'Incorrect proxy address "%s"'%self.proxy)

else:
host, port = self.host, self.port

from twisted.internet import reactor

if self.scheme == 'https':
from twisted.internet.ssl import ClientContextFactory

contextFactory = ClientContextFactory()
reactor.connectSSL(host, port, self, contextFactory)

else:
reactor.connectTCP(host, port, self)
Этот код вырван из контекста (моего проекта), так что я его не тестировал, если будут ошибки — обращайтесь, разберемся.
Для работы с этой HTTPClientFactory теперь не стоит использовать вызов reactor.connectTCP, для установления соединения вызовите метод connect этой фабрики, а так же, при создании фабрики, не забудьте указать какой прокси вы хотите использовать:
factory = HTTPClientFactory('http://python.su/',
proxy = 'localhost:3128')
factory.connect()

2008-10-09

Кодировка в html5lib

Есть такая замечательная библиотека html5lib, а предназначена она для обработки, в том числе не валидного (не корректного) HTML. Пакет так же имеет код для сериализации DOM, ElementTree, BeautifulSoup и другой хрени в HTML, но этой его частью я не пользуюсь.

Вот простенький пример, для парсинга HTML в DOM:
from html5lib.html5parser import HTMLParser
from html5lib.treebuilders.dom import TreeBuilder

dom = HTMLParser(tree = TreeBuilder).parse(html)
Где html — файловый объект или строка. Собственно это все.

Следует отметить, что это замечательная библиотека в состоянии самостоятельно определить кодировку документа одним из нескольких способов, в том числе «самым правильным», используя значение тега meta. Но вот незадача, «самый правильный» способ берет только первые 512 байт для анализа и, если заголовок большой и тег с указанием кодировки находится за границей в 512 байт, то кодировку определить нет шансов.

Решить проблему можно таким вот хаком:
from html5lib.inputstream import HTMLInputStream

HTMLInputStream.numBytesMeta = property(
lambda self: 1024,
lambda self, value: None)
HTMLInputStream.numBytesChardet = property(
lambda self: 2048,
lambda self, value: None)

del HTMLInputStream
Где numBytesMeta это и есть ограничение при сканировании meta, а numBytesChardet это ограничение при сканировании HTML другим методом, какой анализ проводится, я не разбирался. Эти атрибуты настраиваются при инициализации экземпляра HTMLInputStream и тут же используются, так что другого способа перекрыть эти значения нет, не считая, конечно, варианта с переопределением и полным переписыванием метода __init__ и использованием «хитрых свойств». Я умолчал про цифры в лямбдах, но вы и сами о их смысле догадываетесь.

2008-06-01

Удивительно безграмотный тест

По вопросам и результатам этого теста можно судить, что я обязан иметь лицензию на винду (и прочий коммерческий софт), даже если у меня её нет. Я обязан покупать игры и голливудские фильмы, когда они мне не нужны. А лицензионная чистота и страх перед законом превыше моей дружбы. Так то ;-).

Расписал по пунктам свои ответы.

SmartMoney
Пират ли вы?

Вы пират широкого профиля.
срок

SmartMoney, рассмотрев все обстоятельства дела, учтя как отягчающие (подчеркнув характер рецидивности совершенных преступлений и умышленность совершенных деяний), так и смягчающие вину обстоятельства (ваше чистосердечное признание), положительные характеристики, путем частичного сложения наказаний и, руководствуясь сложившейся судебной практикой, определил Ваш приговор: штраф 3 миллиона рублей и год тюрьмы.

Пройти тест

2008-05-10

SSH-туннель

Пару дней назад решал вопрос по подключению к удаленному MySQL серверу через SSH-туннель. По этому поводу решил разродиться короткой памяткой (для себя, для вас) о том как этот тунель организовать под Linux. Уверен, что установить и запустить SSH демон на сервере у вас не составит труда, так же вы уже установили клиент на своем клиенте. Вообще, все очень просто. Ни сервер, ни клиент, которые вы хотите подружить через туннель (я говорю о ПО, а не о машинах как таковых), не должны быть специально обучены работать с туннелем, они и знать о нем не будут. Все будет работать в штатном режиме, как будто и нет никакого туннеля. Что ж, делаем в своем любимом терминале, на клиентской машине, так:
$ ssh -f -N -L4787:example.org:8787 user@server.org

Все, теперь несколько комментариев:

  • 4787 - Этот порт будет открыт на локальной машине, используйте его для доступа к вашему серверу приложения (MySQL, PostgreSQL и т.д.), используйте тот клиент, который предназначен для работы с этим сервером.

  • example.org:8787 - Это удаленный сервер, общение с которым вы и шифруете. Понимайте так, что порт 8787 (в данном примере) на удаленной машине будет транслироваться в 4787 на вашем клиенте.

  • user@server.org - Тут все как обычно. Это машина, на которой установлен SSH-сервер, user - пользователь на этом сервере. Шифрованный канал будет организован именно до этой машины, а вот от неё до example.org трафик шифроваться не будет, будет использован уже ваш сетевой протокол. Обычно example.org и server.org это один и тот же сервер (конечно же используется одно и то же имя или localhost вместо example.org).


По всем остальным ключам и, если вам нужны подробности, обращайтесь к man'у:
$ man ssh
Туннель можно сделать и с помощью PuTTY - почитайте инструкцию по подключению к MySQL, там все можно по скринам понять, если у вас с английским туго.

p.s. Совсем забыл. Респект и уважуха нашим ветеранам. Всех с праздником.

2008-05-08

DVD-файлы в DVD-видео

Linux мне нравится все больше и больше.
Довольно не предусмотрительно натаскал DVD-фильмов в свое время, теперь, когда возникло желание залить обратно это дело и получить нормальный DVD-Video, возникла проблема. Натаскал, это значит выгрузил все что находится в VIDEO_TS (хорошо, что сообразил и взял не только VOB'ы :-), а не сделал образ диска.
Что бы сделать из этой коллекции DVD-Video не достаточно просто скопировать файлы в папку VIDEO_TS и захреначить это дело на диск, работать не будет, во всяком случае не на всех проигрывателях. Образ DVD-Video делается очень просто, достаточно воспользоваться утилем mkisofs с ключом -dvd-video, и все. Образ готов, осталось залить его на диск вашим любимым способом, наслаждайтесь качественным видео :-).

2008-05-06

Аналог start в Linux

start, я так назвал скрипт в линухе. Некоторые консольные приложения, например сервера, удобнее запускать в отдельном терминале, а не в том, в котором ты работаешь в данные момент. Банальный пример - при разработке клиент-серверного приложения мне из far/mc приходится запускать как сервер (я работаю с Python) так и клиент, при этом нет желания открывать руками отдельный терминал, запускать там mc, выбирать нужный скрипт, давить на него Enter'ом (до вчерашнего дня я делал именно так, потом мне надоело и начал думать :-). В Far все делается просто - жмем Shift + Enter и приложение запускается в отдельном окне (я говорю про консольные). Для Linux мне пришлось написать несложный sh-скрипт, который выполняет приложение в xterm:
#!/bin/sh
xterm -title "$*" -geometry 100x25 -e bash --login -c "$*" &

Очень удобно :-).

2008-03-21

Переезд на RAID

Задумал вчера вернуться на свой RAID. Со времени установки Linux (т.е. когда я начал с ним серьезно работать, это Debian GNU/Linux 4.0 Etch) на отдельном винте (он служил как переносной, как запаска и т.д.) я так с ним и работаю. Винту примерно 7 лет и хотя, если верить SMART'у, то он в отличном состонии, но вот хотелось использовать массив из винтов по моложе. Мой RAID, это Promise FastTrak TX2000, ничего особенного из себя не представляет, есть интересные показатели по работе, но никаких космических скоростей :-).
Вообщем линух замечательно на нем завелся (ядро 2.6.23 с драйвером для массива dmraid), с GRUB так же не возникло проблем. Проблемы возникли когда я решил перетасовать (изменить, переместить и добавить) разделы. Пришлось потратить несколько часов, что бы создать все разделы руками, т.е. с использованием шестнадцатиричного редактора. И тут я задумался, а есть ли для линуха нормальный редактор диска и не сделать ли мне свой редактор, всем редактором редактор :-) ?

fdisk

Из-за этой заразы я потерял сегодня пару часов. Все никак не мог понять в чем дело.
Задача состояла в изменении размера ntfs раздела (нужно было его уменьшить). Делал все по инструкции. Выполнил ntfsresize, удалил и создал (с тем же начальным сектором) раздел заново с помощью fdisk. Тут начались проблемы. Дело в том что fdisk (во всяком случае моя версия, GNU Fdisk 1.0) выравнивает границы сектора по размеру дорожки (в моем случае это 63 сектора), ну и выводит информацию так же её выравнивая. Мой раздел не был выравнен (создан установищком w2k :-). Соответственно я получил не достоверную информацию и, используя тот же fdisk, не мог настроить раздел с точностью до сектора.
Я не знаю как создает разделы parted, но, хотя бы, информацию он выводит точную, до сектора. Исправлять все ошибки приходилось так же как и в DOS :-), руками (hex редактором).

2008-01-25

OpenID

Сделал вчера OpenID аутентификацию на Nevow. Получился модуль с минимальными зависимостями (собственно в проекте Neweb я планирую делать именно такие модули и пакеты, т.е. с минимальными связями между собой) от сторонних пакетов и полностью независимый от Neweb (хотя эта ситуация может измениться :-). Правда кроме аутентификации нет ничего, не сообщается даже прошла ли она успешна, а возникающие ошибки будут показаны очень не кашерно. Собственно, докрутить обработку ошибок не сложно, сложнее докрутить её правильно.
Сегодня займусь оптимизайцией (кешированием) и, если будет время, сделаю пользовательские профили и черновую авторизацию пользователей в системе. Я планирую оставить "вход" только по OpenID, а регистрация (создание постоянного профиля) будет производиться только после первого входа (и по желанию пользователя) иначе пользователю будет предоставлен временный профиль с некоторым набором прав. Я только что придумал эти два профиля и чем они отличаются сейчас сказать не могу :-).