Архив за ‘Одминское’ категория

Рассылка-таки удалась!

Август 25th, 2009

Сегодня повторно разослал письма обратившимся в ЦеСТ по этой форме: http://www.centercest.ru/noindex/exec/oem.run

Заранее извиняюсь перед теми, кому рассылаемое письмо пришло более одного раза: вследствие слишком активной рассылки почтовые сервисы (например, mail.ru) заблокировали письма как спам. Также были проблемы с настройками postfix, которые были исправлены.

Шаблон рассылаемых писем:

» Читать дальше: Рассылка-таки удалась!

Вот так…

Август 24th, 2009

На провайдера надейся, а сам не плошай…

Хотел сделать рассылку письма-уведомления по базе в связи этим.

И скрипт написал, и всё сделал. Ан-нет, подвёл провайдер, у которого ВНЕЗАПНО слетел reverse DNS.

В результате, мейл-сервисы режектят меня как спамера. Хорошо хоть ещё в RBL-ки не попал. Придётся ждать, пока пропишут Reverse DNS, и каяться мейл-сервисам, что я, на самом деле, боролся за благое дело.

Прошу прощения у ЦеСТ за такой FAIL и за задержку рассылки.

Миграция на WordPress

Август 22nd, 2009

Итак, как обещал, пишу свои впечатления от миграции на WordPress.

Прежде всего хочу акцентировать внимание на то, почему я всё же решил «слинять» с LiveJournal. Окончательной причиной такого решения стала тотальная кривость движка ЖЖ, которая меня очень сильно поражает. Почему я для того, чтобы удалить запись, должен жать на 3 кнопки (править — удалить — согласен) вместо того, чтобы воспользоваться всего двумя (удалить — согласен). Зачастую даже путаешься в интерфейсе для того, чтобы совершить простейшую операцию — перейти из личного кабинета в блог и наоборот. Ну а также не удовлетворяют тормоза в работе, сильная перегруженность контента ЖЖ и ВНЕЗАПНО появившаяся реклама.

Тем не менее, недостатки, как выяснилось, у WordPress тоже в наличии, но они не такие большие.
Прежде всего претензии к плагинам, работающими с ЖЖ: ни lj-xp, ни lj-user работать нормально не хотели. Ну если в lj-xp всё не так страшно и ограничивается только мелкими патчами кода, неработающего на новой версии PHP, то о плагине lj-user можно сказать только то, что автор вообще не знал, чего писал. Это просто БЫДЛОКОДИНГ, и результат этого быдлокодинга тупо вешал движок WordPress при, казалось бы, элементаной операции обработки текста. Заведомо практически не зная PHP, я написал нормальный плагин lj-user, который не вгоняет в вечный цикл движок WordPress, и именно поэтому считаю стирание исконного автора из комментариев справедливым.

Именно поэтому я публикую исправленные версии плагинов у себя на сервере:
LJ CrossPost (lj-xp).
LJ User (lj-user).

В общем, надеюсь, вам эти плагины тоже помогут.

SSH over HTTP proxy

Июль 30th, 2009

Ввиду того, что инет на даче пионерский, а работать по ssh всё же иногда нужно, искал способ работы по SSH через http-proxy.

И нашёл хороший вариант: использование тулзы под названием corkscrew
Собирается она легко и не требует особых хитростей в настройке. Для этого достаточно отредактировать файл ~/.ssh/config.
Для доступа к myhost.zone конфига будет выглядеть примерно следующим образом:

Host myhost.zone
ProxyCommand corkscrew proxy-address proxy-port %h %p

Если же потребуется аутентификация прокси, то необходимо создать файл (например, ~/.ssh/proxyauth) и записать в нём строчку:

username:password

Сама же конфига SSH изменится так:

Host myhost.zone
ProxyCommand corkscrew proxy-address proxy-port %h %p ~/.ssh/proxyauth

После этого можно спокойно коннектиться на нужный хост:

sadko@sadko:~>ssh myhost.zone

С отпуска!

Июль 22nd, 2009

Подключил-таки инет на даче.
Стоимость 80 копеек за мегабайт впечатляет.
Немного выводит из себя качество: доступ в сеть только через proxy (по имени пользователя и паролю), в результате чего пока могу глядеть только сайты.
Пытался поднять socks через dante, да что-то не клеится.
Собственно, пробую на такой конфиге:

route {
        method: username
        from: 0.0.0.0/0   to: 0.0.0.0/0   via: 192.168.0.1 port = 3128
        command: connect                 # only thing a httproxy supports.
        proxyprotocol: http_v1.0
}

При этом, переменные окружения установлены как надо:

sadko@sadko:~> export | grep SOCKS
declare -x SOCKS_PASSWORD="********"
declare -x SOCKS_USERNAME="********"

В результате получаю вот такую фигню

Это пипец. Это просто пипец.

Июль 4th, 2009

Стал внезапным участником переезда. Смена 24 квадратных метров жилища на 17 (UPD: 15) — это полная жп…
Простите те, кому что-то в ближайшее время обещал. Скорее всего, не выполню обещания в срок.
Особенно прошу прощения у klark973 , так как, скорее всего, так и не успею написать скрипт к отъезду.

А сейчас пока я большей частью в офлайн. И http://xskernel.org/ тоже временно не пашет.

NVIDIA twin view???

Май 21st, 2009

Вчера протрахался с NVidia TwinView(C)(R)(TM).
Проблема хитрая: есть монитор на ноуте 1280×800 и есть проектор с разрешением 1024×768. Нужно вывести изображение с ноута на проектор с масштабированием 1200×800 -> 1024×768, желательно пропорциональным.
Выяснил, что nvidia linux drivers пока не умеют масштабировать изображение в режиме отображения clone.
То есть, уменьшить 1200×800 -> 1024×768 не получится, зато сделал хитро — просто отцентровал второй монитор по первому. Ну и фиг с ним, что картинка обрезана. Кстати, OpenOffice.org оказался не дурак и вывел презентацию в разрешении проектора (на котором будет демонстрироваться презентация), то есть, 1024×768.

Вот логичный вопрос: миллионы треугольников, пикселей и текселей в секунду, но что мешает сделать нормальную систему масштабирования для X Server? Кстати, насколько я помню, под вендой это ещё на GeForce’ах вторых было.

Может, я чего-то упустил и не знаю истинного лекарства?
Советы приветствуются.

Закопать!

Май 13th, 2009

Всё больше и больше Acer вызывает у меня ненависть.

Почему же? А вот почему. Сегодня ходил знакомиться с новой аппаратурой, которую нам выделили в универе на кафеду в связи с переездом. И увидел… гламурненькие асеры. Посмотрел: да, корпус смотрится модно, клавиатурка и мышка в комплекте красивые. На всех машинах Vista Buisness, чтоб её.

Решил проверить на вшивость, врубил новый комп, который планируется отдать под шлюз. Vista что-то там пыхтела минут 15-20, потом выдала-таки лицензионное соглашение. Соглашаться, ессно, ни с лицензией Microsoft, ни с Acer, не стал, вставил openSUSE 11.0 installation DVD и в консоли глянул /proc/cpuinfo, free, lspci, lsusb и пр. Был приятно удивлён: проц Core 2 Quad, 2 гига оперативы, винт на 500 гиг, всё железо на матери интеловское. Это обещало установку без геморроя. Задумался: не уж то Acer что-то дельное выпустили? Хаха, щаз.

Поставил систему быстро: снёс все разделы (в том числе и скрытый) и разметил диск: /boot, /, swap, extended, /home. Система встала быстро, без глюков и гемора (благо иксы и десктопманагеры ставить не надо). Понравился новый гламурный дизайн yast.

Ок, после перекомпиляции ядра решил ребутнуться, проверить его работоспособность. А вот фиг. Груб вывалился в консоль. Ну, думаю, консоль — и ладно, ща вручную бутанёмся и поправим. А вот фиг. Груб орёт, что раздел /boot у меня имеет код 0×27, а не 0×83. Задумался. Ну, чего не бывает: может, инсталлер взглючил. Бутанулся опять с DVD, запустил fdisk, прописал вручную код 0×83, записал на хард, замонтировал, отмонтировал, прочитал ещё раз fdisk’ом таблицу: всё ок. Ребутаюсь… Та же херь: код партиции опять стал 0×27. Отмечу, что описалово скрытой партиции с Vista хранится на том же месте. Прошёлся ещё раз fdisk’ом — не помогло. Полез в BIOS: может, там это можно отключить. Не нашёл. Вот скажите, какими уродами нужно быть, чтобы встроить в BIOS код, который прописывает код партиции 0×27 (то есть, скрытого раздела висты)? Если кто знает, как от этого избавиться, подскажите.

Это ладно. Помимо прочего, на компе в BIOS зашита такая интересная фигня, как Intel (C)(R)(TM) Active Management Technology. Подумал, может она гадит. Решил отключить, для чего пришлось прочесть следующий мануал очень сомнительного содержания:

Free Image Hosting at www.ImageShack.us

Free Image Hosting at www.ImageShack.us

Почему сомнительного? Да потому что это называется не иначе как «Настрой троянца на своём компе». Особенно порадовало требование открыть определённые порты в брандмауэре. И вот такие компьютеры будут стоять практически на каждой кафедре и в каждой лаборатории в университете (!). Лично я считаю, что это — пипец.

Ну и ещё один документ на закуску:

Free Image Hosting at www.ImageShack.us

Кстати, ни одного мануала на русском так и не было, что как бэ намекае.

Спросил своих на кафедре, на кого писать заявление об отказе от ОС на компьютере. Сказали, что пока никому. ОК, подождём.

Hand-made синхронизация репозиториев Subversion

Март 29th, 2009

Несмотря на то, что репозиторий ОС XSystem мигрировал ко мне на домашний сервер, всё же хорошо было бы хранить бэкапы на каком-нибудь удалённом сервере.
Для этого я решил воспользоваться уже имеющимся репозиторием subversion на http://sourceforge.net/.

Идея работы такая: раз в сутки мой репозиторий должен синхронизироваться с удалённым репозиторием. При этом, все изменения в одном репозитории должны однозначно отражаться на другом. С версии subversion 1.4 появилась такая тулза, как svnsync, но она для моего случая не подходит: оба репозитория не предоставляют прямого доступа к svnroot.

Поэтому, немного порывшись в гугле, решил прибегнуть к собственному механизму синхронизации. Идея простая: раз в сутки сливается содержимое первого и второго (будем называть source и destination) репозитория. После этого сверяем содержимое source-репозитория с содержимым destination-репозитория: создаём несуществующие каталоги и копируем несуществующие файлы. Файлы, имеющие различные контрольные суммы md5, также перезаписываем. Но это не всё. После того, как мы влили новое файло в локальное дерево destination-репозитория, мы должны удалить из него те файлы, которых уже нет в source-репозитории. Для этого осуществляем обратную сверку снимка destination-репозитория с source-репозиторием и удаляем из него лишние файлы.

В результате всё это было сведено к скрипту на PERL.

#!/usr/bin/perl

use strict;

my @blacklist   =
(
    qr(^\.svn|\/\.svn$),
    qr(^\.{1,2}$|\/\.{1,2}$)
);

my $src_path  = 'xsystem';
my $dst_path  = 'xskernel-sync';
my $svn_user  = '';
my $svn_pass  = '';

# Update repositories
`svn update $src_path`;
`svn update $dst_path`;

# now search files in src_path and compare to dst_path

add_files();
remove_files();

`svn commit $dst_path -m "Synchronization commit" --username $svn_user --password $svn_pass`;

Как видно, работа скрипта достаточно примитивна. Для его работы нужно иметь два рабочих снимка репозитория: source и destination. У меня source-репозиторий находится в каталоге xsystem, а destination — в каталоге dst_path.
Скрипт сначала обновляет снимки репозиториев, затем осуществляет вливание новых файлов в destination-репозиторий при помощи функции add_files(). После этого удаляются устаревшие файлы и каталоги из destination-репозитория функцией remove_files() и производится коммит изменений в destination-репозиторий.

Дело осталось за малым — разобрать функции добавления и удаления файлов и каталогов. Для этого сначала напишем функцию, которая получает md5sum файла:

sub md5sum
{
    my $fname = shift;
    if (open PIPE, "md5sum $fname |")
    {
        my $line =
;
        close PIPE;
        my ($sum) = ($line =~ /^(\w+)\s+/o);
        return $sum;
    }
    return undef;
}

В принципе, ничего нового. Вызывается утилита md5sum и анализируется её вывод.

Также необходимо игнорировать каталоги ".svn", "." и "..", для чего вводится массив @blacklist и пишется функция банинга файлов:

sub ban_file
{
    my $src_file = shift;
    foreach (@blacklist)
    {
        ($src_file =~ $_) and
            return 1;
    }
    return undef;
}

После этого можно спокойно разобрать функцию add_files():


sub add_files
{
    my @directories = ();
    my $curr_dir = '';

    do
    {
        # Открываем каталог
        if (opendir DIRHDL, "$src_path$curr_dir")
        {
            CYCLE: # Читаем содержимое каталога
            while (my $fname = readdir DIRHDL)
            {
                # Баним ненужные файлы
                my $src_file = "$src_path$curr_dir/$fname";
                (ban_file($src_file)) and
                    next CYCLE;

                my $dst_short = "$curr_dir/$fname";
                my $dst_file  = "$dst_path$dst_short";

                # Файл является каталогом?
                if (-d $src_file)
                {
                    # необходимо проверить, что он есть в destination-репозитории
                    unless (-d $dst_file)
                    {
                        # если каталога нет - его нужно создать
                        print "mkdir   $dst_short\n";
                        `mkdir -p $dst_file`;
                        `svn add $dst_file`;
                    }

                    # Запомним каталог для того, чтобы в будущем его просмотреть
                    push @directories, $dst_short;
                }
                else
                {
                    # проверяем, существует ли файл в destination-репозитории
                    unless (-e $dst_file)
                    {
                        # файл не существует, его нужно скопировать и добавить
                        print "add     $dst_short\n";
                        `cp -f $src_file $dst_file`;
                        `svn add $dst_file`;
                    }
                    else
                    {
                        # файл существует, вычисляем md5sum обоих файлов
                        my $sum1 = md5sum($src_file);
                        my $sum2 = md5sum($dst_file);

                        # если суммы не совпадают - заменяем файл новым
                        if ($sum1 ne $sum2)
                        {
                            print "replace $dst_short\n";
                            `cp -f $src_file $dst_file`;
                        }
                    }
                }
            }
        }
        else
        {
            print "Can't open dir $src_path$curr_dir\n";
        }

        # закрываем каталог и получаем следующий каталог, который следует обработать
        closedir DIRHDL;
        $curr_dir = shift @directories;
    }
    while (defined $curr_dir); # крутимся, пока в списке присутствуют обрабатываемые каталоги.
}

При удалении функция будет очень похожа, только теперь надо осуществлять поиск файлов в destination-репозитории и смотреть, есть ли они в source-репозитории:

sub remove_files
{
    my @directories = ();
    my $curr_dir = '';

    do
    {
        # опять же, открываем каталог destination-репозитория
        if (opendir DIRHDL, "$dst_path$curr_dir")
        {
            CYCLE: # читаем файлы
            while (my $fname = readdir DIRHDL)
            {
                # баним недопустимые diren'ы
                my $src_file = "$dst_path$curr_dir/$fname";
                (ban_file($src_file))
                    and next CYCLE;

                my $src_short = "$curr_dir/$fname";
                my $dst_file  = "$src_path$src_short";

                # проверяем, является ли это каталогом
                if (-d $src_file)
                {
                    # проверяем, существует ли этот каталог в source-репозитории
                    unless (-d $dst_file)
                    {
                        # каталога нет - удаляем его из destination-репозитория
                        print "rmdir   $src_short\n";
                        `svn delete $src_file`;
                    }
                    else
                    {
                        # каталог существует, запоминаем его для дальнейшей обработки
                        push @directories, $src_short;
                    }
                }
                else
                {
                    # Это обычный файл, проверяем, есть ли он в source-репозитории
                    unless (-e $dst_file)
                    {
                        # Файла нет, удаляем его из destination-репозитория
                        print "unlink  $src_short\n";
                        `svn delete $src_file`;
                    }
                }
            }
        }
        else
        {
            print "Can't open dir $dst_path$curr_dir\n";
        }

        # Закрываем каталог, получаем следующий
        closedir DIRHDL;
        $curr_dir = shift @directories;
    }
    while (defined $curr_dir);
}

Недостаток этой тулзы один: если файл был перемещён, то он будет распознан как новый файл. Хотя, я не думаю, что файлы и каталоги так часто перемещаются в логически корректно построенном дереве проекта.

Как я поднимал SVN

Март 29th, 2009

Собственно, данный пост я решил написать после ночных бдений с SVN. Да, у меня были проблемы, которые пришлось решить, возможно, нестандартными методами, но зато теперь всё работает так, как я хотел.

Управление репозиторием

Итак, для всего этого нам нужнен сам Apache (я использовал Apache 2) и дополнительные модули: dav и dav_svn.

Помимо этого, я ещё поставил просматривалку репозитория ViewVC, с которой потом долго и провозился.

Для того, чтобы заставить работать subversion через http, достаточно сделать следующее (делал в OpenSUSE 10.3):
Сначала включаем модули при помощи a2enmod:


a2enmod dav
a2enmod dav_svn

Теперь можно перезагрузить конфигу апача (либо через restart, либо через reload):


/etc/init.d/apache2 restart

или


/etc/init.d/apache2 reload

После этого необходимо сконфигурировать виртуальный хост. Лично я хотел, чтобы у меня SVN-репозиторий был как отдельный поддомен в домене xskernel.org — то есть, svn.xskernel.org.

Для этого заводим отдельный виртуальный хост в апаче:


<VirtualHost *:80>
    ServerName svn.xskernel.org
    ErrorLog    /var/log/apache2/svn-error.log
    TransferLog /var/log/apache2/svn-access.log

    <Location /svn >
      DAV svn
      SVNPath /home/svn/repositories/svn.xskernel.org
      SVNListParentPath on
      AuthType Basic
      AuthName "XSystem Kernel Team repository"
      AuthBasicProvider file
      AuthUserFile /home/svn/auth/svn.xskernel.org.htpasswd
      SetOutputFilter DEFLATE

      <LimitExcept GET PROPFIND OPTIONS REPORT>
        Require valid-user
      </LimitExcept>
    </Location>

</VirtualHost>

Как видно, здесь в конфиге заводится локейшн /svn, который используется для работы DAV. Именно DAV позволяет полноценно работать с репозиторием через http.

Рассмотрим некоторые параметры:
SVNPath задаёт каталог, в котором располагается репозиторий, который будет ассоциирован с данным виртуальным хостом. Естественно, сам SVNRoot я спрятал (не стал использовать SVNRootPath).
AuthUserFile — файл, в котором будут в дальнейшем храниться пользователи и хэши их паролей, которым будет разрешён доступ в SVN.
LimitExcept накладывает ограничения на все команды кроме GET, PROPFIND, OPTIONS и REPORT, требуя авторизации (Require valid-user).

Отлично, теперь нужно завести соответствующий репозиторий. Я решил хранить все репозитории в отдельном каталоге /home/svn/repositories, поэтому создал репозиторий таким образом:


mkdir -p /home/svn/repositories
svnadmin create /home/svn/repositories/svn.xskernel.org

Отлично, теперь репозиторий есть, надо сделать авторизацию. Для этого создаю файл паролей и завожу в нём пользователя:


mkdir -p /home/svn/auth
touch /home/svn/auth/svn.xskernel.org.htpasswd
htpasswd2 /home/svn/auth/svn.xskernel.org.htpasswd username

Теперь апачу нужно дать права на пользование репозиторием и файлами паролей, для чего присваиваю всем файлам пользователя, под которым работает апач:


chown -Rv webserver:web /home/svn

Сохраняем конфигурационный файл виртуальных хостов апача, перезагружаем конфигурацию по reload, и пробуем зайти по адресу http://svn.xskernel.org/svn/. WebDAV работает!

Просматривание репозитория

Вот с просматривалкой у меня и возникло много проблем. Хотелось, чтобы при заходе на http://svn.xskernel.org/ автоматически запускалась просматривалка, при этом она отображала бы только тот репозиторий, который ассоциирован с данным виртуальным хостом. Я перепробовал много различных вариантов и, в конце-концов, остановился на том, что изложу ниже.

WebDAV я поставил штатными средствами OpenSUSE — из репозитория, после чего забрал его из /srv/www и переместил в каталог /home/svn.
Для своего виртуального хоста завёл отдельную конфигу /home/svn/viewvc-svn.xskernel.org.conf, в которой прописал следующие параметры:


# Доступные репозитории для просмотра
svn_roots:
        svn.xskernel.org : /home/svn/repositories/svn.xskernel.org
# Репозиторий, который следует просматривать по умолчанию
default_root = svn.xskernel.org
# Адрес обратной связи
address = team@xskernel.org
# Не использовать корень как компонент URL (то есть, не отображаются остальные репозитории в корне)
root_as_url_component = 0
# Путь к файлам с шаблонами отображения веб-страницы
template_dir = /home/svn/viewvc/svn.xskernel.org/templates
# компонент URL, по которому будут располагаться ресурсы для просматривалки (картинки и пр.)
docroot = /viewvc-docroot

Теперь заводим скрипт, который цепляет эту конфигу, копируя стандартный:


cp /home/svn/bin/cgi/viewvc.cgi /home/svn/bin/cgi/viewvc-svn.xskernel.org.cgi

И редактируем строки, прописывая:


LIBRARY_DIR = r"/home/svn/lib"
CONF_PATHNAME = r"/home/svn/viewvc-svn.xskernel.org.conf"

Теперь скрипт /home/svn/bin/cgi/viewvc-svn.xskernel.org.cgi хватает конфигу /home/svn/viewvc-svn.xskernel.org.conf.
После всего этого заводим свои темплейты для ViewVC:


mkdir -p /home/svn/viewvc/svn.xskernel.org
cp -R /home/svn/templates /home/svn/viewvc/svn.xskernel.org
cp -R /home/svn/templates/docroot /home/svn/viewvc/svn.xskernel.org/viewvc-docroot

Прикручивание ViewVC к апачу

Теперь надо в каталоге /home/svn/viewvc/svn.xskernel.org завести файл index.html, который редиректит на подкаталог "/viewvc":


<pre>
<html><head><META HTTP-EQUIV="Refresh" CONTENT="0; URL=/viewvc"><head>
<body></body>
</html>
</pre>

Сделано это так потому, что если сам Апач осуществит редирект, SVN-клиент начнёт ругаться, что не может выполнить PROPFIND при импорте репозитория (проверено уже часовыми бдениями над mod_rewrie).

Прописываем ViewVC в конфиге виртуального хоста:


<VirtualHost *:80>
    #...
    ScriptAlias /viewvc "/home/svn/bin/cgi/viewvc-svn.xskernel.org.cgi"
    Alias / /home/svn/viewvc/svn.xskernel.org/

    <Directory /home/svn/viewvc/svn.xskernel.org/ >
        Order allow,deny
        Allow from all
        DirectoryIndex index.html
    </Directory>
</VirtualHost>

Параметр ScriptAlias указывает, какой скрипт следует запускать, когда URL содержит "/viewvc".

Перезагружаем конфигу апача, пробуем: http://svn.xskernel.org/.
Грузится страничка index.html, которая автоматом нас редиректит на http://svn.xskernel.org/viewvc/ и запускается скрипт /home/svn/bin/cgi/viewvc-svn.xskernel.org.cgi .

Заключение

Как видно, не всё так красиво в моей настройке, как хотелось бы. Если есть соображения/советы, как сделать лучше, то я их внимательно выслушаю.

Тем не менее, репозиторий ОС XSystem переехал с SourceForge.net ко мне на домашний сервер. Работает на порядок быстрее, чем тормозной сервис от SourceForge.net. Однако, от SF.net я не стал отказываться, а сделал его зеркалом моего репозитория. Как — в следующем посте.