Saturday, July 10, 2010

Кое-что об использовании локалей в перле

Столкнулся недавно с такой проблемой:  при подключении (use) некоторого модуля X, print и printf начинали использовать символ "," в качестве разделителя при печатании чисел с дробной частью. Модуль X использовал функцию POSIX::setlocale, после чего локаль менялась глобально.

Документация по данному вопросу откровенно врёт. Например perldoc -f printf говорит следующее:
If use locale is in effect, and POSIX::setlocale() has been called, the character used for the decimal separator in formatted floating-point numbers is affected by the LC_NUMERIC locale.

На самом деле, use locale для этого нафиг не нужна:
# perl -MPOSIX -e 'setlocale(LC_ALL,"ru_RU.CP1251"); printf "%.2f", 1.5'
1,5

В общем, получается, что установив  таким образом LC_NUMERIC в любом месте программы, мы меняем форматирование всех дробных чисел.

Во ибежание таких побочных эффектов, следует сохранять прежнюю локаль и восстанавливать ее в нужном месте программы.

Update: Еще один косяк - POSIX::strftime. Согласно документации

By default, Perl ignores the current locale. The use locale pragma tells Perl to use the current locale for some operations: ... The POSIX date formatting function (strftime()) uses LC_TIME .


Однако и для strftime "use locale" не нужна:

LANG=de_DE.UTF-8 perl -MPOSIX -E 'say strftime "%A %B %e %H:%M:%S %Y", localtime'
Dienstag März 15 17:19:54 2011


Все потому, что функция С strftime использует текущую локаль, и Perl особо не заморачивается с прагмой use locale.

Wednesday, July 7, 2010

Perl: как обмануть strict

Обнаружил забавный баг в перле, связанный с прагмой strict.
Пример неработающего кода:

# perl -e 'package MyPackage; use strict; __PACKAGE__->{foo} = 1'
Global symbol "%MyPackage" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.


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

# perl -e 'package My::Package; use strict; __PACKAGE__->{foo} = 1'


Ошибки нет. Интерпретатор  считает этот код валидным.

Sunday, July 4, 2010

FreeBSD: Базовая настройка ProFTPD

Настройка proftpd для обновления web-сайтов по FTP.

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

# cd /usr/ports/*/proftpd && make install clean

После установки добавляем proftpd_enable="YES" в /etc/rc.conf для того, чтобы FTP-сервер запускался при старте системы.

Далее, правим конфиг (/usr/local/etc/proftpd.conf).  Мне понадобились следующие опции:

  • RequireValidShell off
    Не требовать, чтобы пользователь имел валидный шелл.

  • ListOptions -a
    Отображать скрытые файлы в листингах (например, .htaccess).

  • AuthUserFile /usr/local/etc/ftpd.passwd
    passwd-файл с "виртуальными" ftp-пользователями (к нему вернемся чуть позже).

  • AuthOrder mod_auth_file.c
    Использовать наш passwd-файл (и только его) для аутентификации.

  • DefaultRoot ~
    Корневая папка по умолчанию соответствует домашнему каталогу пользователя (chroot).


Создаем файл /usr/local/etc/ftpd.passwd скриптом ftpasswd:

# cd /usr/local/etc
# ftpasswd --passwd --name user1 --home /var/dir1 --shell /usr/sbin/nologin --uid 80
# ftpasswd --passwd --name user2 --home /var/dir2 --shell /usr/sbin/nologin --uid 80


Здесь я нарочно устанавливаю обоим юзверям uid 80 (такой же, как у апача), чтобы не было проблем с правами.

Можно стартовать сервер:

# /usr/local/etc/rc.d/proftpd start