понедельник, 16 июня 2008 г.

PHP $argv ахтунг.

argv.php
#!/usr/local/bin/php -q
print_r($argv);

FreeBSD:
% ./argv.php a b c
Array
(
[0] => ./argv.php
[1] => a
[2] => b
[3] => c
)

Gentoo Linux:
$ ./argv.php a b c
Array
(
[0] => a
[1] => b
[2] => c
)


WTF?



UPD:
http://bugs.php.net/bug.php?id=44673

среда, 23 апреля 2008 г.

OpenOffice Macro security button bug #81230

В OpenOffice не работает кнопка Macro Security.

1) находим ~/.openoffice.org2/user/registry/data/org/openoffice/Office/Common.xcu
2) в секцию
<node oor:name="Security">
<node oor:name="Scripting">
...
</node>
</node>

вставляем свойство:
<prop oor:name="MacroSecurityLevel" oor:type="xs:int">
<value>1</value>
</prop>

Дислог по-прежнему не будет показываться, зато можно будет использовать макросы.

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

понедельник, 21 апреля 2008 г.

Потрошим Interbase .gdb файлы

Interbase поразил очевидностью своей эксплуатации.

Была задача извлечь из .gdb файла содержимое и перелить в другую БД. Сразу скажу, что с Interbase я вообще никогда не сталкивался, поэтому рассуждения, что называется, с нуля.

Может быь я действительно такой криворукий, но мне не удалось ни запустить JDBC драйвер, ни воспользоваться родным клиентом.

Не буду упоминать все исхоженные пути, просто изложу самый короткий и работающий:

# emerge firebird -v
# cp /path/to/your/database-file.gdb /usr/lib/firebird/

На любителя, можно еще для гарантии добавить:
# chmod 666 /usr/lib/firebird/database-file.gdb

$ fbsql -u SYSDBA -p masterkey /usr/lib/firebird/database-file.gdb -ch WIN1251
Database: /usr/lib/firebird/database-file.gdb, User: SYSDBA
SQL>

Ура! В этот момент мы имеем работающую БД и консольку, откликающуюся на запросы.

Почему базу скопировали в /usr/lib/firebird ?
Потому что иначе не будет работать нестандартная кодировка. Можно настроить т.н. embeded вариант, но он предполагает наличие ./intl/fbintl.so в папке с программой, т.е. fbsql.
Я пробовал добавить это в папку с файлом базы, т.к. в Windows это кажись работало (как это делают в программах от Борланда, прости, Господи):
$ mkdir ./intl
$ cp /usr/lib/firebird/fbintl.so ./intl/
однако нифига счастливого не произошло. Будет дешевле скопировать саму базу куда положено.

Проверим, все ли так, как нам надо:
SQL> show tables;
SQL> select * from any_table;

Ну, а дальше все банально:
$ echo "select * from any_table;" > query.sql
$ fbsql -u SYSDBA -p masterkey /usr/lib/firebird/database-file.gdb -ch WIN1251 -i query.sql -o result-1251.txt -pag 99999
$ iconv -f cp1251 -t utf8 result-1251.txt > result-utf.txt

Теперь в result-utf.txt имеем выковыренные запросом данные. Изменение их вида и перегон в другую БД оставлю читателю.

P.S. все вышенаписанное проделано на Gentoo.

среда, 12 марта 2008 г.

PHP Daemon

А теперь немного извращений: демон на PHP.

ЧАСТЬ 1. ПИШЕМ ДЕМОНА.
Описание команд читать в мануалах. По-возможности, я даю на них ссылки.

declare(ticks=1);

$g_signals = array(
  'SIGTERM' => 0,
  'SIGHUP' => 0,
);

$g_ppid = null;
$g_pid = null;

dmn_sys_init(); // сердце демона!

$g_ppid = posix_getppid(); // pid родителя
$g_pid = posix_getpid(); // pid дочернего (текущего) процесса

// поехали!
while(1){
  // делаем что-то полезное.

  if($g_signals['SIGTERM'] == 1) // если получен сигнал завершения процесса, то не спеша, не паникуя тихонечко заканчиваем работу и выходим.
    break;

  if($sleep_time > 0)
    sleep(1); // спать одну секунду (на самом деле это идеологически не правильно, но для шаблона подойдет)
}

function dmn_sys_init(){
  global $g_pid;

  // 1. создаем дочерний процесс. при одном работающем это может быть не нужно, но если планируется запуск одного контрольного и нескольких рабочих процессов, то этот код необходим.
  if(-1 == ($g_pid = pcntl_fork()))
    exit("Could not fork.\n");

  // очень важный момент! Здесь определяем в каком мы процессе после разветвления.
  if($g_pid != 0){
    // 2. мы в родительском процессе
    // тут нам нужно отслеживать завершение дочерних процессов.
    // делается это банально просто: при создании процесса накручиваем счетчик дочерних процессов
    // при завершении дочернего процесса уменьшаем счетчик. Когда дочерних не осталось - выходим.
    // ждать завершения можно командой pcntl_wait.
    // написание этого кода я оставлю читателю в качестве домашного задания

    // для тех, кому лень думать есть приятные новости - дочерние процессы можно не ждать,
    // а делать в лучших традициях мира животных - выкидывать их из гнезда и тихонько помирать.
    exit("The end of parent process.\n");
  }

  // 3. мы в дочернем процессе!
  // отцепляем процесс от консоли
  if(-1 == posix_setsid())
    exit("Could not detach from terminal.\n");

  // устанавливаем хуки для обрабатываемых сигналов
  if(!pcntl_signal(SIGTERM, "dmn_sys_sig_handler"))
  exit("Could not setup SIGTERM handler.\n");

  if(!pcntl_signal(SIGHUP, "dmn_sys_sig_handler"))
  exit("Could not setup SIGHUP handler.\n");
}

// функция-хук обработки сигналов от операционной системы
function dmn_sys_sig_handler($signo)
{
  global $g_signals;

  switch ($signo){
  case SIGTERM:
    $g_signals['SIGTERM'] = 1;
    break;
  case SIGHUP:
    $g_signals['SIGHUP'] = 1;
    break;
  default:
    $g_signals['OTHER'] = $signo;
  }
}


ЧАСТЬ 2. ПИШЕМ RC СКРИПТЫ.
Здесь пример примитивнейшего RC скрипта для Gentoo.
RC скрипт и PHP файлы записать в /etc/init.d/my-php-daemon и /usr/lib/my-php-daemon соответственно.

#!/sbin/runscript

depend() {
  # выставляем зависимости
  need net
}

start() {
  # показываем юзеру что мы делаем
  ebegin "Starting my PHP daemon"

  # ведем лог
  echo --------------------- >> /var/log/my-php-daemon/rc.log
  date >> /var/log/my-php-daemon/rc.log

  # запускаем демоненка
  php-cgi -f /usr/lib/my-php-daemon/index.php >> /var/log/my-php-daemon/rc.log

  # конец
  eend $?
}

stop() {
  # показываем юзеру что мы делаем
  ebegin "Stopping my php daemon"
  # останавливаем демона так - ищем процесс, выполняющий файл /usr/lib/my-php-daemon/index.php и посылаем ему сигнал SIGTERM.
  # внимание! если таких процессов несколько, то все они получат сигналы SIGTERM.
  pkill -TERM -f /usr/lib/my-php-daemon/index.php

  # ведем лог
  date >> /var/log/my-php-daemon/rc.log
  echo --------------------- >> /var/log/my-php-daemon/rc.log

  # конец
  eend $?
}


Таким образом все варнинги и ошибки PHP будут сыпаться в /var/log/my-php-daemon/rc.log, но, к сожалению, без даты. Добавить дату - это будет читателю второе домашнее задание.

Конечно, мануал не претендует на полноту и безупречность, но это лучше, чем ничего. А еще лучше для простого изучения.

БОНУС-ТРЕК
Поскольку PHP бывает весьма не предсказуем, то для контроля работы демона можно написать небольшой cron скриптик:

$g_vs_gw = "http://gw1.viasms.ru?"
$g_vs_eid = "12345";
$g_vs_password = "secure_word";

$g_needed = array(
  'my-php-daemon' => array(
    'regexp'=>'/php-cgi.+my-php-daemon/',
    'reset_cmd'=>'/etc/init.d/my-php-daemon zap --nocolor',
    'start_cmd'=>'/etc/init.d/my-php-daemon start --nocolor'
  ),
);

// fill array with system fields
$needed = array();

foreach($g_needed as $key=>$val){
  $needed[$key] = $val;
  $needed[$key]['running'] = 0;
}

$exec = shell_exec("ps -C php-cgi -o pid= -o command=");
$pss = explode("\n", $exec);

foreach($needed as $key=>$val)
  if(!$val['running'])
    foreach($pss as $ps)
      if(preg_match($val['regexp'], $ps))
        $needed[$key]['running'] = 1;

foreach($needed as $key=>$val){
  if(!$val['running']){
    print date("Ymd-His") . "\n";

    print shell_exec($val['reset_cmd']);
    $cmdresult = shell_exec($val['start_cmd']);
    print $cmdresult;

    $msg = $key . ' service is down. ' . $cmdresult;
    $pass = md5(md5($g_vs_password) . $msg);

    $url = $g_vs_gw . '?' .
      'eid=' . urlencode($g_vs_eid) .
      '&pass=' . urlencode($pass) .
      '&msg=' . urlencode($msg);

    print $url . "\n";
    readfile($url);
    print "\n";
  }
}


Этот скрипт во время своего запуска проверяет все демоны, указанные в массиве $g_needed. Если один из них не работает, то скрипт сбрасывает его состояние (zap) и запускает снова. Ориентировано, опять таки, на дистрибутив Gentoo. Для подстройки для вашего дистрибутива подкрутите элементы массива reset_cmd и start_cmd.

О результате выполнения пишет лог и отправляет SMS сообщение с текстом о состоянии запуска.
В качестве SMS шлюза используется сайт viasms.ru. Для этого в переменных $g_vs_eid и $g_vs_password надо указать id и пароль события.

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


my-php-daemon service is down. Starting my PHP daemon [ ok ].


И вы сможете дальше спокойно пить пиво :О)

понедельник, 3 марта 2008 г.

Синхронизация Google

Для ищущих способы синхронизации сервисов Google с телефоном, компьютером, конкретным клиентом:

GCALDaemon is an OS-independent Java program that offers two-way synchronization between Google Calendar and various iCalendar compatible calendar applications. GCALDaemon is primarily designed as a calendar synchronizer but it can also be used as a Gmail notifier, Address Book importer, Gmail terminal and RSS feed converter.

пятница, 29 февраля 2008 г.

Как сделать зашифрованный диск

Дано: Gentoo Linux
Рабочая болванка - 1 штука.

Для начала убедимся, что у нас в ядре поставлены нужные галочки (версия 2.6.23):
BLK_DEV_LOOP=y
Prompt: Loopback device support
Location: -> Device Drivers -> Block devices

BLK_DEV_CRYPTOLOOP=y
Prompt: Cryptoloop Support
Location -> Device Drivers -> Block devices -> Loopback device support

В разделе Cryptographic API указать используемые алгоритмы шифрования, в нашем примере:
CRYPTO_TWOFISH=y
Prompt: Twofish cipher algorithm
Location:
-> Cryptographic API

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

(добавлено 20080423): Проверить софт: sys-apps/util-linux должна быть с USE флагом loop-aes.

Затем:
1. создаем чистый файл под размер болванки. В примере ниже будет создан файл 1024*4200k байт.


# dd if=/dev/zero of=./disk.dat bs=1024 count=4200k

2. создаем шифрованный loop device и вводим пароль для шифрования:

# losetup -e twofish256 /dev/loop0 ./disk.dat
Password:

3. создаем файловую систему на вновь созданном устройстве

# mkfs.ext2 /dev/loop0

4. монтируем устройство

# mount /dev/loop0 /mnt/secure-disk

5. После этого в папку /mnt/secure-disk копируем все необходимые данные.
Оставшееся место можно, как обычно, контролировать командой df.

6. Затем размонтируем и удаляем устройство

# umount /mnt/test && losetup -d /dev/loop0

Полученный таким образом файл disk.dat можно записать на болванку. Важно помнить, что файлы больше 2Гб требуют на диске файловую систему UDF, которая, если не ошибаюсь, в Windows не поддерживается. Проблему можно обойти сделав несколько фалов размером до 2 гб и записать диск в обычном формате ISO.

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

(http://knopkodav.blogspot.com/2008/02/blog-post.html)

# losetup -e twofish256 /dev/loop0 ./disk.dat
Password:
# mount /dev/loop0 /mnt/secure-disk -t ext2
...
# umount /dev/loop0
# losetup -d /dev/loop0


Пока не изученные альтернативы:
loop-aes

пятница, 8 февраля 2008 г.

Drupal тип поля password_confirm

Никогда не ставьте
'#maxlength' => ххх,

для необязательных типов полей
'#type' => 'password_confirm',

получите ошибку
"warning: mb_strlen() expects parameter 1 to be string, array given in /var/www/localhost/htdocs/includes/unicode.inc on line 370."

Это связно с тем, что Друпал проверят длинну поля, а поскольку password_confirm - массив из двух полей, то имеем некорректный параметр передаваемый в mbstrlen.

Немного бэктрейса (лишнее вырезано):
warning: mb_strlen() expects parameter 1 to be string, array given in /var/www/html/localhost/htdocs/includes/unicode.inc on line 370.


Array
(
[#type] => password_confirm
[#description] => To change the current password, enter the new password in both fields.
[#maxlength] => 30
[#size] => 40
[#post] => Array
(
[sz_personal_pass] => Array
(
[pass1] =>
[pass2] =>
)
)
[#name] => sz_personal_pass
[#id] => edit-sz-personal-pass
[#value] => Array
(
[pass1] =>
[pass2] =>
)
[#needs_validation] => 1
)

среда, 9 января 2008 г.

Static /dev on Gentoo OpenVZ VPS

(в модификации от 28 июля 2008)

В OpenVZ VPS по-умолчанию почему-то не содержит девайсов /dev/random, /dev/urandom.
Недостаток легко устраняется несколькими действиями:

----- СПОСОБ 1:

1) редактируем файл /vz/private/123/etc/conf.d/rc
в нем меняем RC_DEVICES="static"

После этого подразумевается, что все устройства этой VPS в /dev вы создадите руками.
Этим и займемся:
2) mknod --mode 666 /vz/private/123/dev/ptmx c 5 2
3) mkdir /vz/private/123/dev/pts
4) rm -f /vz/private/123/dev/null
mknod --mode 666 /vz/private/123/dev/null c 1 3
5) mknod --mode 444 /vz/private/123/dev/urandom c 1 9
6) mknod --mode 444 /vz/private/123/dev/random c 1 8

Последние два нужно обязательно, но по-отдельности опционально.
Реально можно отказаться от использования /dev/random, если поставить флаг USE="urandom" (справедливо для arp). Но, иной софт может и не понять.

Все это можно делать не останавливая VPS, поскольку делается в папке private.

После изменений перезапускаем:
# vzctl stop 123
# vzctl start 123

----- СПОСОБ 2 (спасибо анонимному читателю за подсказку, этот способ проще и корректнее):

1) редактируем файл /vz/private/123/etc/conf.d/rc
в нем меняем RC_DEVICE_TARBALL="yes"

2) После изменений перезапускаем VPS:
# vzctl stop 123
# vzctl start 123

Внутри самой VPS создаем устройства:
2) mknod --mode 444 /dev/urandom c 1 9
3) mknod --mode 444 /dev/random c 1 8

Теперь при ребуте они будут создаваться автоматически.

-----

Дополнительные ссылки:
http://forum.openvz.org/index.php?t=msg&goto=5140
http://wiki.openvz.org/Physical_to_VE#.2Fdev.2Furandom
http://mlblog.osdir.com/openvz.user/2006-01/index.shtml