Category Archives: система

Делаем дамп БД и отсылаем себе на почту

Введение

Здравствуйте.

Наша задача – периодически делать дамп указанной базы данных (БД) и отсылать нам на почту, чтобы в случае чего можно было восстановиться в любой момент времени.

Для этого достаточно штатных средств Linux‘а.

DB.SH

Итак, составляем простой шелл скрипт – текстовый файл, назовём его db.sh, и делаем его исполняемым:

$ vim /var/adm/cron/db.sh
$ chmod +x /var/adm/cron/db.sh

Учтём, что в папке /var/adm/cron находятся крон-задачи, т.е. периодически выполняемые на нашем сервере, этот каталог не доступен из Интернета.

Вот полное содержимое db.sh:

#!/bin/sh
cd /var/adm/cron/
echo "**" `date +'%Y-%m-%d %H:%I:%S'` "I am db.sh:" `id` >> log.txt
mysqldump -h localhost -u dbuser -pmypassword mydbase > db_dump.sql
bzip2 -f db_dump.sql
date +'%Y-%m-%d %H:%I:%S' | mutt -s 'mydbase backup' -a db_dump.sql.bz2 -- mymail@yandex.ru

Что мы тут делаем:
1. Переходим в каталог, где находится наш скрипт: /var/adm/cron
2. В лог (файл log.txt) выведем текстовое сообщение с текущей датой/времени в формате YYYY-MM-DD HH:mm:ss (год-месяц-число час-минуты-секунды), произвольным сообщением (I’m db.sh) и ид юзера, под которым запущен скрипт. Делать это конечно же не обязательно.
3. Делаем бэкап базы mydbase из-под пользователя dbuser с паролем mypassword (этот пользователь конечно же должен иметь доступ к указанной БД) и сохраняем его в файле db_dump.sql.
4. Сжимаем полученный бэкап архиватором BZIP2 (он сжимает несколько лучше, чем штатный GZIP). Флаг -f (force, форсировать) говорит о том, чтобы перезаписывать старый архив в случае его наличия.
5. Отправляем сообщение на адрес mymail@yandex.ru в виде текущей даты/времени со вложением только что заархивированного дампа базы данных. Замечу, что сам архивированный дамп БД мы оставляем в текущем каталоге, на всякий случай.

MUTT

Самое интересное – 5-ый шаг, мы используем консольный почтовик mutt, хотя это довольно популярная и древняя утилита, в базовые дистрибутивы она обычно по-умолчанию не входит, и её нужно установить командой своего менеджера пакетов, например, для Debian/Ubuntu:

# apt-get install mutt

Также обратите внимание на версию mutt‘а, мы используем версию 1.5.21:

# mutt -v
Mutt 1.5.21 (2010-09-15)
...

Дело в том, что для других версий команда отправки письма с сообщением может отличаться, например для Mutt 1.4.xx версии я использовал такую команду:

date | /usr/local/mutt-1.4.2.3/mutt -s 'mydbase backup' -a db_dump.sql.bz2 mymail@yandex.ru

Обратите внимание на разницу передачи пайпа от команды date к mutt‘у. Как говорится, найдите 10 отличий.

Если вы не являетесь админом на сервере, как вариант собрать mutt из исходников, и указывать абсолютный путь к нему. Я так делал на SpaceWeb‘е. Либо загуглить статически линкованный mutt. Я сейчас в первой 20-ке не смог найти статического mutt‘а по запросу `mutt static build download`. В этом случае можно собрать статический mutt у себя на локальном компьютере, инструкции как это сделать найти можно, и перенести его на сервер.

Также mutt можно заменить на утилиту mail, входящую в пакет mailx (или один из его производных). Если на сервере доступна команда mail, отослать наш дамп БД как вложение можно командой:

$ mail -s "mydbase backup" -a "db_dump.sql.bz2" "mymail@yandex.ru" <<< $(date +"%Y-%m-%d %H:%I:%S")

Параметры здесь практические такие же, что и у mutt: -s – тема, -a – аттачмент.

CRON

Теперь добавим вызов скрипта в cron. Мне достаточно делать дамп БД раз в сутки, настрою вызов скрипта каждый день, в 5:13 утра:

$ crontab -e
13 	5 	* 	* 	* 	/var/adm/cron/db.sh

Либо как вариант закинуть db.sh в папку /etc/cron.daily, если есть к ней доступ. Рабочей папкой для скрипта всё равно останется /var/adm/cron, всю работу он будет делать там.

SPLIT

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

postdrop: warning: uid=0: File too large
sendmail: fatal: root(0): message file too big
Сообщение отправить не удалось, процесс-потомок вернул 75 (Deferred.).
Сообщение отправить не удалось.

Ага, этого рано-поздно следовало ожидать. Дамп нашей базы оказался слишком велик для передачи по электронной почте. Тут у нас есть пара вариантов (как хорошо, что жизнь компьютерная почти всегда предоставляет нам несколько решений одной и той же проблемы, что касается программирования или системного администрирования, вот бы в реальной жизни всё было бы так же).
1. Увеличить макс.размер отправляемых писем. Если Вы админ, это можно легко сделать. mutt, впрочем как и mail(x), использует установленный в системе mail-transport-agent (MTA), из коих наиболее распространёнными на сегодня пожалуй являются Postfix и Exim4. Пример с Postfix‘ом как увеличить максимальный размер отсылаемых писем:

# postconf | grep message_size_limit
message_size_limit = 10240000
# postconf -e "message_size_limit = 51200000"
# postconf | grep message_size_limit
message_size_limit = 51200000

Сперва мы узнали макс.размер письма, который оказался равен 10 мегабайт, затем увеличили его до 50 мегабайт. Да, у Postfix‘а по-умолчанию размер письма (message) включая возможные аттачи максимум 10 мегабайт. Размер последнего дампа БД, который удалось отправить, был равен 8.6 мегабайт, файлы большего размера уже не отправлялись, что довольно странно, так как до 10 мегабайт было ещё не так скоро. Хотя на самом деле аттачи отправляются в uuencoded (или base64-encoded) формате, и если мы закодируем так наш последний полученный по почте дамп, то получим размер 11,970,592 байта в chunk_split(base64_encode($attach)) или размер 12,052,444 байт при использовании convert_uudecode($attach) – были использованы стандартные PHP функции. В обоих случаях размер превышает заданный по умолчанию в Postfix‘е 10,240,000 байт.

ОК, если мы увеличим макс.разрешенный размер письма до 50 мегабайт, то мы получим какое-то время, возможно в несколько лет (если наша БД не очень быстро пополняется), прежде чем мы превысим макс.допустимый объём.

Да, тут несколько возможных проблем – рано или поздно аттач (в смысле письмо с ним) опять превысит макс.допустимый размер и перестанет отправляться, второе – принимающий сервер может со своей стороны ограничивать размер принимаемых писем. Третье – вы можете не быть админом на сервере и повысить максимальный размер письма. В скобках замечу, что, указав message_size_limit = 0 вы снимете ограничение на максимальный размер письма.

Во всех этих случаях нас выручит split, старый добрый split. Давайте будем пилить наш аттач например по 5 мегабайт и кусками отправлять нам на почту. Делается это примерно так:

split -b 5M db_dump.sql.bz2 dump5M_
 
for i in dump5M_*
do
date +'%Y-%m-%d %H:%I:%S' | mutt -s 'mydbase backup' -a $i -- mymail@yandex.ru
done
 
# почистим за собой
rm dump5M_*

Таким образом новый готовый скрипт db.sh будет выглядеть так:

#!/bin/sh
cd /var/adm/cron/
echo "**" `date +'%Y-%m-%d %H:%I:%S'` "I am db.sh:" `id` >> log.txt
mysqldump -h localhost -u dbuser -pmypassword mydbase > db_dump.sql
bzip2 -f db_dump.sql
split -b 5M db_dump.sql.bz2 dump5M_
 
for i in dump5M_*
do
date +'%Y-%m-%d %H:%I:%S' | mutt -s 'mydbase backup' -a $i -- mymail@yandex.ru
done
 
# почистим за собой
rm dump5M_*

При задании в split имени dump5M_ мы получаем файлы вида dump5M_aa, dump5M_ab, dump5M_ac и т.п. Чтобы склеить при случае полученные куски, можно обойтись штатными средствами системы:

В Windows (кавычки в именах файлов обязательны):

C:\Users\Andrey\Desktop> copy /b "dump5M_aa" + "dump5M_ab" db.sql.bz2

В Linux:

$ cat dump5M_aa dump5M_ab > db.sql.bz2

или:

$ cat dump5M_a* > db.sql.bz2

И в случае применения split’а есть недостаток, если, например, размер дампа 50 мегабайт, то мы будем каждый день отсылать/получать по 10 писем, не знаю, хорошо это или плохо. Как вариант – отсылать дамп БД на резервный сервер, к примеру с помощью команды scp, но это пожалуй уже другая история.

На сим всё, раскланиваюсь, т.к. наша задача выполнена на 100% и мы можем теперь спать спокойно, не боясь краха нашего сервера и утери нашей драгоценной базы данных с кредитной историей наших клиентов.

Спокойной ночи, сладких снов, если уже ночь, чашки кофе и стакана апельсинового сока, если утро, бокала пива с жаренными креветками, если обед, бутылки виски или Шардоне, если вечер.

Инсталлируем и конфижим DKIM с Postfix на Debian/Ubuntu

Перевод с https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy

Введение

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

  • Сервер явлется открытым почтовым релеем (open mail relay), позволяющим любому пересылть через него тонны писем
  • IP адрес сервера находится в черном списке (blacklisted)
  • Сервер не имеет Fully Qualified Domain Name (FQDN) и соотв. записи PTR
  • the Sender Policy Framework (SPF) DNS record отсуттствует или неверно сконфижен
  • the DomainKeys Identified Mail (DKIM) отсутствует ил опять же неверно настроен

Это основные требования, проверяемые многими спам-фильтрами (включая SpamAssasin).

Это руководство (tutorial) описывает инсталляцию и конфигурирование OpenDKIM: открытую имплементацию DKIM.

Важно: замените `example.com` на имя своего домена во всех примерах ниже. Команды выполняются от имени суперпользователя (su). При необохдимости используйте sudo, если предпочитаете не быть суперзверем на своём сервере. Также на системах Ubuntu вместо apt-get можно использовать apt с подобным синтаксисом. (Это была вставка от меня, Андрея Царя, простите за вольности).

Postfix и Dovecot должны быть уже установлены и сконфижены как следует (руководства (tutorial)), имя хоста и the FQDN заданы (tutorial, tutorial) и запись SPF на своём месте (tutorial).

О DKIM

DKIM – это интернет-стандарт, который позволяет частному лицу либо организации связать имя домена с email-сообщением.. То есть в какой-то мере это метод, подтверждающий достоверность и легальность отправляемого письма. В своей сути, DKIM основан на асимметричной криптографии. Mail Transfer Agent (MTA) отправителя подписывает каждое исходящее сообщение приватным ключом. Принимающая сторона получает публичный ключ из поля DNS и удостоверяется в том, что тело сообщения и некоторые заголовки не были изменены после подписывания письма.

Инсталлируем OpenDKIM

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

apt-get update
apt-get upgrade

Инсталлируем OpenDKIM и его зависимости:

apt-get install opendkim opendkim-tools

Конфижим OpenDKIM

Теперь надо создать несколько файлов для конфигурироания OpenDKIM.

Итак, начнём с основного файла конфигурации:

vim /etc/opendkim.conf

Добавьте строки в конец conf-файла (каждый параметр будет объяснен позже). Также вы можете выбрать другой номер порта для опции Socket. Убедитесь, что порт не используется другим приложением. Также замечу, что ключевое слово milter обозначает mail filter, т.е. почтовый фильтр.

AutoRestart             Yes
AutoRestartRate         10/1h
UMask                   002
Syslog                  yes
SyslogSuccess           Yes
LogWhy                  Yes

Canonicalization        relaxed/simple

ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/KeyTable
SigningTable            refile:/etc/opendkim/SigningTable

Mode                    sv
PidFile                 /var/run/opendkim/opendkim.pid
SignatureAlgorithm      rsa-sha256

UserID                  opendkim:opendkim

Socket                  inet:12301@localhost
  • AutoRestart: перезапуск фильтра при ошибке
  • AutoRestartRate: макс.рестарт рэйт, если будет превышен, фильтр остановится; 10/1h – 10 рестартов в час позволено
  • UMask: полный доступ группе с ID = UserID и позволяет другим читать и запускать файлы, в данном случае позволна модификация файла Pid.
  • Syslog, SyslogSuccess, *LogWhy: включают детальный логинг для syslog
  • Canonicalization: определяют методы канонизации, используемые при подписи писем simple метод практически не позволяет модификации, тогда как relaxed допускает минимальные изменения, такие как замена whitespace; relaxed/simple – заголовок письма будет обрабатываться алгоритмом relaxed, а тело письма – simple алгоритмом
  • ExternalIgnoreList: определяет внешние хосты, которые могут слать почту ч/з сервер как один из подписанный оменов без проверки
  • InternalHosts: определяет список внутренних хостов, чью почту не проверяем, но подписываем
  • KeyTable: карта имен ключей для ключей подписи
  • SigningTable: списки применяемых к письмам подписей основанных на адресе, найденном в поле From: заголовка
  • Mode: описывает режимы; в нашем случае milter действует как подписчик (signer) (s) и контроллер (verifier) (v)
  • PidFile: путь к Pid-файлу который содержит ид процесса
  • SignatureAlgorithm: выбирает алгоритм подписывания писем
  • UserID: opendkim процесс выполнятеся от имени данного юзера и группы
  • Socket: milter будет слушать на сокете, определённом здесь, Posfix будет слать письма на проверку и подпись к opendkim ч/з этот сокет; 12301@localhost определяет TCP сокет, слушающий на localhost, порт 12301. Если порт 12301 занят, можно использовать любой другой свободный порт

Эта простая конфигурация позволяет подписывать сообщения для одного или более доменов, для ознакомления с другими опциями посмотрите здесь.

Соединяем milter с Postfix:

vim /etc/default/opendkim

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

SOCKET="inet:12301@localhost"

Просим Postfix использовать наш milter:

vim /etc/postfix/main.cf

Убедимся что следующие две строчки присутствуют в файле и не закомментированы:

milter_protocol = 2
milter_default_action = accept

Вполне возможно что фильтры (SpamAssasin, Clamav etc.) уже используются Postfix; если да, до добаляем наш milter через запятую, вот так (не забываем про номер порта как в opendkim.conf):

smtpd_milters = unix:/spamass/spamass.sock, inet:localhost:12301
non_smtpd_milters = unix:/spamass/spamass.sock, inet:localhost:12301

Если же данных параметров нет, просто добавляем следующие две строчки в файл:

smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301

Создаём структуру каталогов, содержащих доверенные хосты, таблицы ключей и криптования

mkdir -p /etc/opendkim/keys

Определяем доверенные хосты:

vim /etc/opendkim/TrustedHosts

Будем использовать этот файл для определения ExternalIgnoreList и InternalHosts, сообщения с этих хостов, доменов и IP-адресов являются доверенными и будут подписаны.

Т.к. наша основная конфигурация объявила TrustedHosts как файл регулярных выражений (refile), мы можем использовать wildcard’ы, т.е. *.example.com означает, что сообщения с поддоменов example.com войдут также в число доверенных, как и сообщения с самого домена example.com.

Добавьте следующие строки в новый файл. Множество доменов может быть добавлено здесь:

127.0.0.1
localhost
192.168.0.1/24

*.example.com

#*.example.net
#*.example.org

Создаём таблицу ключей:

vim /etc/opendkim/KeyTable

Таблица ключей содержит каждую пару селектор/домен и путь к их приватным ключам. Любая строка из латинских буквa и цифр может быть селектором, в нашем примере мы используем mail.

mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private

#mail._domainkey.example.net example.net:mail:/etc/opendkim/keys/example.net/mail.private
#mail._domainkey.example.org example.org:mail:/etc/opendkim/keys/example.org/mail.private

Создём таблицу подписи:

vim /etc/opendkim/SigningTable

Этот файл используется для объявления адресов домен/email и их селекторов.

*@example.com mail._domainkey.example.com

#*@example.net mail._domainkey.example.net
#*@example.org mail._domainkey.example.org

Генерируем public и private ключи

Перейдём в каталог с ключами:

cd /etc/opendkim/keys

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

mkdir example.com
cd example.com

Генерируем ключи:

opendkim-genkey -s mail -d example.com

-s определяет селектор, а -d определяет домен, эта команда создаст два файла:mail.private это наш private ключ, а mail.txt содержит public ключ.

Поменяем владельца private ключа на opendkim:

chown opendkim:opendkim mail.private

Добавим public ключ к DNS записям домена

Откроем mail.txt:

vim mail.txt

public ключ определён под параметром p. Пример:

mail._domainkey IN      TXT     ( "v=DKIM1; k=rsa; "
          "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5N3lnvvrYgPCRSoqn+awTpE+iGYcKBPpo8HHbcFfCIIV10Hwo4PhCoGZSaKVHOjDm4yefKXhQjM7iKzEPuBatE7O47hAx1CJpNuIdLxhILSbEmbMxJrJAG0HZVn8z6EAoOHZNaPHmK2h4UUrjOG8zA5BHfzJf7tGwI+K619fFUwIDAQAB" )  ; ----- DKIM key mail for example.com

Скопируйте этот ключ и добавьте запись TXT для своего домена в DNS:

Имя: mail._domainkey.example.com.

Text: "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5N3lnvvrYgPCRSoqn+awTpE+iGYcKBPpo8HHbcFfCIIV10Hwo4PhCoGZSaKVHOjDm4yefKXhQjM7iKzEPuBatE7O47hAx1CJpNuIdLxhILSbEmbMxJrJAG0HZVn8z6EAoOHZNaPHmK2h4UUrjOG8zA5BHfzJf7tGwI+K619fFUwIDAQAB"

Измения в DNS могут занять какое-то время до вступления в силу.

Перезапуск Postfix и OpenDKIM:

service postfix restart
service opendkim restart

Мои поздравления! Мы успешно настроили DKIM для нашего почтового сервера!

Конфигурация может быть протестирована отправкой пустого email’а на check-auth@verifier.port25.com. Если всё работает как должно, мы должны будем получить письмо, где среди прочего должна присутствовать строка DKIM check: pass под заголовком Summary of Results.

==========================================================
Summary of Results
==========================================================
SPF check:          pass
DomainKeys check:   neutral
DKIM check:         pass
Sender-ID check:    pass
SpamAssassin check: ham

Также можно послать письмо на наш адрес в Gmail и посмотреть исходники полученного письма, там должна присутствовать строка dkim=pass под заголовком Authentication-Results.

Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of contact@example.com designates --- as permitted sender) smtp.mail=contact@example.com;
       dkim=pass header.i=@example.com;
Создано: П. Себастьян (P. Sebastian)
Перевод: А. Царь (beotiger)

Часовые пояса и расширение tar.lz в Windows

Здравствуйте!

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

function getOptTimeZones($dk_timezone = 0)
{
	// построим select для dk_timezone
	$dk_tzs = array(
-15 => '(GMT -12:00) Эневеток, Кваджалейн',
-14 => '(GMT -11:00) Остров Мидуэй, Самоа',
-13 => '(GMT -10:00) Гавайи',
-12 => '(GMT -9:00) Аляска',
-11 => '(GMT -8:00) Тихоокеанское время (США и Канада), Тихуана',
-10 => '(GMT -7:00) Горное время (США и Канада), Аризона',
-9 => '(GMT -6:00) Центральное время (США и Канада), Мехико',
-8 => '(GMT -5:00) Восточное время (США и Канада), Богота, Лима',
-7 => '(GMT -4:00) Атлантическое время (Канада), Каракас, Ла Пас',
-6 => '(GMT -3:00) Бразилия, Буэнос-Айрес, Джорджтаун',
-5 => '(GMT -2:00) Среднеатлантическое время',
-4 => '(GMT -1:00) Азорские острова, острова Зелёного Мыса',
-3 => '(GMT  0:00) Дублин, Лондон, Лиссабон, Касабланка, Эдинбург',
-2 => '(GMT +1:00) Брюсель, Копенгаген, Мадрид, Париж, Берлин',
-1 => '(GMT +2:00) Афины, Киев, Минск, Бухарест, Рига, Таллин',
0 => '(GMT +3:00) Москва, Санкт-Петербург, Волгоград',
1 => '(GMT +4:00) Абу-Даби, Баку, Тбилиси, Ереван',
2 => '(GMT +5:00) Екатеринбург, Исламабад, Карачи, Ташкент',
3 => '(GMT +6:00) Омск, Новосибирск, Алма-Ата, Астана',
4 => '(GMT +7:00) Красноярск, Норильск, Бангкок, Ханой, Джакарта',
5 => '(GMT +8:00) Иркутск, Пекин, Перт, Сингапур, Гонконг',
6 => '(GMT +9:00) Якутск, Токио, Сеул, Осака, Саппоро',
7 => '(GMT +10:00) Владивосток, Восточная Австралия, Гуам',
8 => '(GMT +11:00) Магадан, Сахалин, Соломоновы Острова',
9 => '(GMT +12:00) Камчатка, Окленд, Уэллингтон, Фиджи');
 
	$s = '';
 
	for($i = -15; $i < 10; $i++) {
		$s .= '<option value="' . $i . '"';
		if($i == $dk_timezone)
			$s .= ' selected';
		$s .= '>' . $dk_tzs[$i] . '</option>';
	}
 
        return $s;
}

То есть мы построили список из option элементов для select‘а для сдвига от МСК. Т.о. (GMT +3:00) Москва, Санкт-Петербург, Волгоград у нас будет иметь значение 0, а всё остальное плюс-минус от этого значения. Переменная $dk_timezone содержит текущий сдвиг, что позвлояет выделить нужный option. Полученный результат надо облечь в select элемент.

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

При поиске готового архивчика с таким зонами я часто натыкался на ссылку http://www.iana.org/time-zones, где якобы представлна вся инфо по теме.

На этом уважаемом сайте действитльено даётся свободная скачка трёх интресных файликов:
Latest version
2016j (Released 2016-11-23)
File Description
tzdb-2016j.tar.lz (380.4kb) Complete Distribution (Data, Code and Extras)
tzdata2016j.tar.gz (313.7kb) Data Only Distribution
tzcode2016j.tar.gz (203.8kb) Code Only Distribution

Заметьте, что два файлика имеют расширение tar.gz, и один, самый интересный, за каким-то лешим имеет расширение .tar.lz. я не знаю, что творится в голове администратора данного ресурса, но выглядит это забавно. Что стукнуло ему в голову самый нужный файлик облечь в расширение .tar.lz, вместо доброго старого .tar.gz или на худой конец такого же доброго и такого же старого и проверенного временем tar.bz2?

Я сейчас пока вишу в Виньде (Windows 10), для распаковки пользуюсь 7zip (http://www.7-zip.org/) – огромная благодарность Игорю Павлову со-товарищи за разработку столь замечательного продукта. tar.gz и tar.bz2 (как и многие другие архивы) он щёлкает как семечки, а вот об tar.lz (по крайней мере на текущий момент, что я сейчас пишу) обламывает свои острые мощные зубки:

7zip fails to open tar.lz archive

Я даже проапгрейдил свой 7zip до версии 16.04, топовой на сегодня – 2016-11-23, т.е. 23 ноября 2016 РХ.

Быстрый гугл вывел на зверя lzip, я где-то нарыл скомпиленную под винду версию – lzip.exe, быстро запустил его в терминале,и вот что он выдаёт, собака:


С:\>lzip -d tzdb.tar.lz
tzdb.tar.lz: file ends unexpectedly at pos 21
lzip: Deleting output file `tzdb.tar', if it exists.
lzip: WARNING: deletion of output file (apparently) failed.

Я перименовал яновский tzdb-2016j.tar.lz в tzdb.tar.lz

Итак, что же делать? Далее гуглим и находим такую страничку: http://mm.icann.org/pipermail/tz/2016-September/024112.html

Вкратце, там человек по имени Oscar van Vlijmen жалуется, что не может открыть файлик lz в windows, такой же бедолага как и я, и упоминает тот же lzip, который я только что описал чуть выше.

Зачем, зачем, зачем админы http://www.iana.org/time-zones запаковали lzip‘ом только один файлик, а не все три тогда уж? Что у них, повторяюсь в третий раз, в головах творится?

Итак, кто-то ему отвечает:

Q: Why did the tachyon cross the road?
A: Because it was on the other side.

К чему это? Сколько лет ответившему так? он считает себя самым умным или самым остроумным? нет слов.

Следующий чуть лучше отвечает Оскару:

> do we get a decent application program with a graphical user interface
You mean, like the other tools we’re using? Like ‘tar’, ‘make’, and ‘cc’? 🙂

С одной стороны он прав,а с другой нет. Если ты выкладываешь файл для всего мира на скачку без явного уклона в одну систему, сделай его максимально доступным для мира, хотя бы для наиболее распространенных систем.

Ладно, этот же человек подсказал, что в CygWin‘е есть lzip, сейас его попробую, он скачивает кучу зависимостей за собой, что обычно для Unix-way. Спасибо ему, всё же он не так плох, как я думал вначале. 🙂 шутка

О, урра, получилось!!

Итак, по шагам, как я распаковал tzdb-2016j.tar.lz с сайта http://www.iana.org/time-zones в Windows 10:

1. Инсталлируем CygWin (https://cygwin.com/install.html), я это сделал в папку E:\cygwin64 – скачиваем setup-x86_64.exe файлик, запускаем его, выбираем папки (e:\cygwin64 для самого Cygwin‘а и e:\cygwin64\_local\ для временных локальных фалов.

2. Далее ищем в фильтре lzip, выбираем пакеты (я выбрал оба пакета, хотя боюсь можно выбрать только сам lzip), нажимаем Next или Далее, он выдаст окошко с зависимостями, которые по умолчанию все выбраны, нажимаем ОК, далее или что там ещё, не помню, и минут через 5 инсталлятор закончит работу.

3. Кидаем в папку e:\cygwin64\home\ВашеИмя\ нужный архивчик (tzdb-2016j.tar.lz)

4. Запускаем e:\cygwin64\Cygwin.bat, делаем ls, чтобы убедиться, что он тут:

$ ls
tzdb-2016j.tar.lz

И даём команду на его распаковку в tar:


$ lzip -d tzdb-2016j.tar.lz

На экран ничего не вывелось, кроме нового приглашения, что для Линукса говорит о том, что всё прошло ОК (хотя это не всегда так есть), т.к. если бы была какая-то ошибка, нам бы об этом с радостью сообщили.

Смотрим ещё ls:

$ ls
tzdb-2016j.tar

7zip fails to open tar.lz archive

О, у нас появился tar архивчик. Пробуем открыть его уже штатными виндовыми методами, через 7zip, и он отлично открывается, показывая список файлов.

Всё, задача решена, можно пойти выпить чая или какао или на худой конец коньяка с кофе. Или кофе без коньяка, до НГ, точнее до 12:00 31 декабря 2016 года я спиртного не потребляю, печень берегу и голову.

На сим кланяюсь. Доброй ночи!

P.S. Да, в итоге, в этом архивчике много всего интересного, но то, что мне нужно – список часовых поясов со сдвигом GMT+- для простого пользователя не оказалось!

Потом я в архиве какого-то форума нашёл приведенный выше (в самом начале поста) список, быстро переделал его под PHP, убрал +-30 минут кое-где, т.к. они мне не были нужны. И так получилась функция getOptTimeZones.

Читаем/пишем бинарники на JavaScript (JScript) для Win Wscript

Да, проблема в том, что JavaScript пытается преобразовать полученные байты в юникод (unicode), и портит большинство байт, которые больше 0x7F. Поэтому при чтении/записи бинарников получается не то, что мы хотим.

Пошарив какое-то время в инете, я нашёл табличку преобразований символов больше либо равным 0x80, но она в итоге оказалась не полной, и мои бинарники читались и писались с ошибками.

В итоге я решил составить свои таблички для преобразования байт. Но вручную искать и записывать байты из – в мне показалось утомительным, поэтому я написал пару небольших скриптов.

Идея такая – создать бинарный файл, состоящий из последовательности байт от 0 до 255, то есть размером 256 байт, а потом распрасить его JavaScript’ом и проанализировать полученные символы.

Пишем краткий сценрий на PHP, ибо PHP всегда под рукой, что в Виньде ,что в Линуксе, что на серверах.

<?php
/* create file of bytes from 0 to 255 */
	$s = '';
	for($i = 0; $i < 256; $i++)
		$s .= chr($i);
 
	file_put_contents('256.dat', $s);

В итоге, мы имеем файл 256.dat, который проанализируем JavaScript’ и составим табличку преобразований на лету.

var name = '256.dat', i; // путь к нашему файлу и переменная д/цикла
 
/* ******************************************
* Используем API AkelPad's Scripts плагина  *
******************************************* */
var bytes = AkelPad.ReadFile(name, 0);	// binary
log('bytes.length=' + bytes.length); // должно быть 256
 
var abytes = bytes.split('');
log('abytes.length=' + abytes.length); // должно быть 256
 
var ascii = '', fromAscii = '', c;
for(i = 0; i < abytes.length; i++) {
        // table asciiCodeAt
        if(i > 127)
	  ascii += 'case 0x' + bin2hex(abytes[i]) +
            ': return 0x' + i.toString(16) + '; break;\n'
	// REVERSE TABLE fromAscii
	c = bin2hex(abytes[i]);
	if(c.length == 3)
		c = '0' + c;
	else
	if(c.length == 2)
		c = '00' + c;
	// count only high values
	if(i > 127)
	  fromAscii += 'case 0x' + i.toString(16) + ': s += \'\\u' +
            c.toUpperCase() + '\'; break;\n'
}
 
log('// ASCII:');
log(ascii)
log('// fromAscii:');
log(fromAscii);
 
function bin2hex(s) {
  //  discuss at: http://phpjs.org/functions/bin2hex/
  // original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // bugfixed by: Onno Marsman
  // bugfixed by: Linuxworld
  // improved by: ntoniazzi (http://phpjs.org/functions/bin2hex:361#comment_177616)
  //   example 1: bin2hex('Kev');
  //   returns 1: '4b6576'
  //   example 2: bin2hex(String.fromCharCode(0x00));
  //   returns 2: '00'
 
  var i, l, o = '',
    n;
 
  s += '';
 
  for (i = 0, l = s.length; i < l; i++) {
    n = s.charCodeAt(i)
      .toString(16);
    o += n.length < 2 ? '0' + n : n;
  }
 
  return o;
}
 
// Логируем текст с помощью AkelPad'овского Log плагина
function log(text)
{
  AkelPad.Call("Log::Output", 4, text + '\n');
}

Потом копируем полученный вывод в отдельный файл, добавляем необохдимую разметку и получаем в итоге полные таблицы преобразований to ASCII и from Ascii Code для JavaScript:

/*
	Needed for reading from binary files
 	See actionUtils.getImageSize method in emmet-app.js
*/
String.prototype.asciiCodeAt = function(i) {
    // charCodeAt returns some bytes translated to unicode characters. 
    // this function means to counteract that.
    switch(this.charCodeAt(i)) {
        case 0x402: return 0x80; break;
				case 0x403: return 0x81; break;
				case 0x201a: return 0x82; break;
				case 0x453: return 0x83; break;
				case 0x201e: return 0x84; break;
				case 0x2026: return 0x85; break;
				case 0x2020: return 0x86; break;
				case 0x2021: return 0x87; break;
				case 0x20ac: return 0x88; break;
				case 0x2030: return 0x89; break;
				case 0x409: return 0x8a; break;
				case 0x2039: return 0x8b; break;
				case 0x40a: return 0x8c; break;
				case 0x40c: return 0x8d; break;
				case 0x40b: return 0x8e; break;
				case 0x40f: return 0x8f; break;
				case 0x452: return 0x90; break;
				case 0x2018: return 0x91; break;
				case 0x2019: return 0x92; break;
				case 0x201c: return 0x93; break;
				case 0x201d: return 0x94; break;
				case 0x2022: return 0x95; break;
				case 0x2013: return 0x96; break;
				case 0x2014: return 0x97; break;
				case 0x98: return 0x98; break;
				case 0x2122: return 0x99; break;
				case 0x459: return 0x9a; break;
				case 0x203a: return 0x9b; break;
				case 0x45a: return 0x9c; break;
				case 0x45c: return 0x9d; break;
				case 0x45b: return 0x9e; break;
				case 0x45f: return 0x9f; break;
				case 0xa0: return 0xa0; break;
				case 0x40e: return 0xa1; break;
				case 0x45e: return 0xa2; break;
				case 0x408: return 0xa3; break;
				case 0xa4: return 0xa4; break;
				case 0x490: return 0xa5; break;
				case 0xa6: return 0xa6; break;
				case 0xa7: return 0xa7; break;
				case 0x401: return 0xa8; break;
				case 0xa9: return 0xa9; break;
				case 0x404: return 0xaa; break;
				case 0xab: return 0xab; break;
				case 0xac: return 0xac; break;
				case 0xad: return 0xad; break;
				case 0xae: return 0xae; break;
				case 0x407: return 0xaf; break;
				case 0xb0: return 0xb0; break;
				case 0xb1: return 0xb1; break;
				case 0x406: return 0xb2; break;
				case 0x456: return 0xb3; break;
				case 0x491: return 0xb4; break;
				case 0xb5: return 0xb5; break;
				case 0xb6: return 0xb6; break;
				case 0xb7: return 0xb7; break;
				case 0x451: return 0xb8; break;
				case 0x2116: return 0xb9; break;
				case 0x454: return 0xba; break;
				case 0xbb: return 0xbb; break;
				case 0x458: return 0xbc; break;
				case 0x405: return 0xbd; break;
				case 0x455: return 0xbe; break;
				case 0x457: return 0xbf; break;
				case 0x410: return 0xc0; break;
				case 0x411: return 0xc1; break;
				case 0x412: return 0xc2; break;
				case 0x413: return 0xc3; break;
				case 0x414: return 0xc4; break;
				case 0x415: return 0xc5; break;
				case 0x416: return 0xc6; break;
				case 0x417: return 0xc7; break;
				case 0x418: return 0xc8; break;
				case 0x419: return 0xc9; break;
				case 0x41a: return 0xca; break;
				case 0x41b: return 0xcb; break;
				case 0x41c: return 0xcc; break;
				case 0x41d: return 0xcd; break;
				case 0x41e: return 0xce; break;
				case 0x41f: return 0xcf; break;
				case 0x420: return 0xd0; break;
				case 0x421: return 0xd1; break;
				case 0x422: return 0xd2; break;
				case 0x423: return 0xd3; break;
				case 0x424: return 0xd4; break;
				case 0x425: return 0xd5; break;
				case 0x426: return 0xd6; break;
				case 0x427: return 0xd7; break;
				case 0x428: return 0xd8; break;
				case 0x429: return 0xd9; break;
				case 0x42a: return 0xda; break;
				case 0x42b: return 0xdb; break;
				case 0x42c: return 0xdc; break;
				case 0x42d: return 0xdd; break;
				case 0x42e: return 0xde; break;
				case 0x42f: return 0xdf; break;
				case 0x430: return 0xe0; break;
				case 0x431: return 0xe1; break;
				case 0x432: return 0xe2; break;
				case 0x433: return 0xe3; break;
				case 0x434: return 0xe4; break;
				case 0x435: return 0xe5; break;
				case 0x436: return 0xe6; break;
				case 0x437: return 0xe7; break;
				case 0x438: return 0xe8; break;
				case 0x439: return 0xe9; break;
				case 0x43a: return 0xea; break;
				case 0x43b: return 0xeb; break;
				case 0x43c: return 0xec; break;
				case 0x43d: return 0xed; break;
				case 0x43e: return 0xee; break;
				case 0x43f: return 0xef; break;
				case 0x440: return 0xf0; break;
				case 0x441: return 0xf1; break;
				case 0x442: return 0xf2; break;
				case 0x443: return 0xf3; break;
				case 0x444: return 0xf4; break;
				case 0x445: return 0xf5; break;
				case 0x446: return 0xf6; break;
				case 0x447: return 0xf7; break;
				case 0x448: return 0xf8; break;
				case 0x449: return 0xf9; break;
				case 0x44a: return 0xfa; break;
				case 0x44b: return 0xfb; break;
				case 0x44c: return 0xfc; break;
				case 0x44d: return 0xfd; break;
				case 0x44e: return 0xfe; break;
				case 0x44f: return 0xff; break;
 
        default: return this.charCodeAt(i);
    }
}
 
/*
	Needed for writing to binary files.
 	See base64.decode method in emmet-app.js
*/
String.fromAsciiCode = function() {
    // reverse for asciiCodeAt() method
    var s = '', i, c = arguments.length;
 
    for(i = 0; i < c; i++)
    	switch(arguments[i]) {
				case 0x80: s += '\u0402'; break;
				case 0x81: s += '\u0403'; break;
				case 0x82: s += '\u201A'; break;
				case 0x83: s += '\u0453'; break;
				case 0x84: s += '\u201E'; break;
				case 0x85: s += '\u2026'; break;
				case 0x86: s += '\u2020'; break;
				case 0x87: s += '\u2021'; break;
				case 0x88: s += '\u20AC'; break;
				case 0x89: s += '\u2030'; break;
				case 0x8a: s += '\u0409'; break;
				case 0x8b: s += '\u2039'; break;
				case 0x8c: s += '\u040A'; break;
				case 0x8d: s += '\u040C'; break;
				case 0x8e: s += '\u040B'; break;
				case 0x8f: s += '\u040F'; break;
				case 0x90: s += '\u0452'; break;
				case 0x91: s += '\u2018'; break;
				case 0x92: s += '\u2019'; break;
				case 0x93: s += '\u201C'; break;
				case 0x94: s += '\u201D'; break;
				case 0x95: s += '\u2022'; break;
				case 0x96: s += '\u2013'; break;
				case 0x97: s += '\u2014'; break;
				//case 0x98: s += '\u0098'; break;
				case 0x99: s += '\u2122'; break;
				case 0x9a: s += '\u0459'; break;
				case 0x9b: s += '\u203A'; break;
				case 0x9c: s += '\u045A'; break;
				case 0x9d: s += '\u045C'; break;
				case 0x9e: s += '\u045B'; break;
				case 0x9f: s += '\u045F'; break;
				//case 0xa0: s += '\u00A0'; break;
				case 0xa1: s += '\u040E'; break;
				case 0xa2: s += '\u045E'; break;
				case 0xa3: s += '\u0408'; break;
				//case 0xa4: s += '\u00A4'; break;
				case 0xa5: s += '\u0490'; break;
				//case 0xa6: s += '\u00A6'; break;
				//case 0xa7: s += '\u00A7'; break;
				case 0xa8: s += '\u0401'; break;
				//case 0xa9: s += '\u00A9'; break;
				case 0xaa: s += '\u0404'; break;
				//case 0xab: s += '\u00AB'; break;
				//case 0xac: s += '\u00AC'; break;
				//case 0xad: s += '\u00AD'; break;
				//case 0xae: s += '\u00AE'; break;
				case 0xaf: s += '\u0407'; break;
				//case 0xb0: s += '\u00B0'; break;
				//case 0xb1: s += '\u00B1'; break;
				case 0xb2: s += '\u0406'; break;
				case 0xb3: s += '\u0456'; break;
				case 0xb4: s += '\u0491'; break;
				//case 0xb5: s += '\u00B5'; break;
				//case 0xb6: s += '\u00B6'; break;
				//case 0xb7: s += '\u00B7'; break;
				case 0xb8: s += '\u0451'; break;
				case 0xb9: s += '\u2116'; break;
				case 0xba: s += '\u0454'; break;
				//case 0xbb: s += '\u00BB'; break;
				case 0xbc: s += '\u0458'; break;
				case 0xbd: s += '\u0405'; break;
				case 0xbe: s += '\u0455'; break;
				case 0xbf: s += '\u0457'; break;
				case 0xc0: s += '\u0410'; break;
				case 0xc1: s += '\u0411'; break;
				case 0xc2: s += '\u0412'; break;
				case 0xc3: s += '\u0413'; break;
				case 0xc4: s += '\u0414'; break;
				case 0xc5: s += '\u0415'; break;
				case 0xc6: s += '\u0416'; break;
				case 0xc7: s += '\u0417'; break;
				case 0xc8: s += '\u0418'; break;
				case 0xc9: s += '\u0419'; break;
				case 0xca: s += '\u041A'; break;
				case 0xcb: s += '\u041B'; break;
				case 0xcc: s += '\u041C'; break;
				case 0xcd: s += '\u041D'; break;
				case 0xce: s += '\u041E'; break;
				case 0xcf: s += '\u041F'; break;
				case 0xd0: s += '\u0420'; break;
				case 0xd1: s += '\u0421'; break;
				case 0xd2: s += '\u0422'; break;
				case 0xd3: s += '\u0423'; break;
				case 0xd4: s += '\u0424'; break;
				case 0xd5: s += '\u0425'; break;
				case 0xd6: s += '\u0426'; break;
				case 0xd7: s += '\u0427'; break;
				case 0xd8: s += '\u0428'; break;
				case 0xd9: s += '\u0429'; break;
				case 0xda: s += '\u042A'; break;
				case 0xdb: s += '\u042B'; break;
				case 0xdc: s += '\u042C'; break;
				case 0xdd: s += '\u042D'; break;
				case 0xde: s += '\u042E'; break;
				case 0xdf: s += '\u042F'; break;
				case 0xe0: s += '\u0430'; break;
				case 0xe1: s += '\u0431'; break;
				case 0xe2: s += '\u0432'; break;
				case 0xe3: s += '\u0433'; break;
				case 0xe4: s += '\u0434'; break;
				case 0xe5: s += '\u0435'; break;
				case 0xe6: s += '\u0436'; break;
				case 0xe7: s += '\u0437'; break;
				case 0xe8: s += '\u0438'; break;
				case 0xe9: s += '\u0439'; break;
				case 0xea: s += '\u043A'; break;
				case 0xeb: s += '\u043B'; break;
				case 0xec: s += '\u043C'; break;
				case 0xed: s += '\u043D'; break;
				case 0xee: s += '\u043E'; break;
				case 0xef: s += '\u043F'; break;
				case 0xf0: s += '\u0440'; break;
				case 0xf1: s += '\u0441'; break;
				case 0xf2: s += '\u0442'; break;
				case 0xf3: s += '\u0443'; break;
				case 0xf4: s += '\u0444'; break;
				case 0xf5: s += '\u0445'; break;
				case 0xf6: s += '\u0446'; break;
				case 0xf7: s += '\u0447'; break;
				case 0xf8: s += '\u0448'; break;
				case 0xf9: s += '\u0449'; break;
				case 0xfa: s += '\u044A'; break;
				case 0xfb: s += '\u044B'; break;
				case 0xfc: s += '\u044C'; break;
				case 0xfd: s += '\u044D'; break;
				case 0xfe: s += '\u044E'; break;
				case 0xff: s += '\u044F'; break;
 
        default: s += String.fromCharCode(arguments[i]);
    }
    return s;
}

Первую табличку мы используем при чтении из бинарного файла средствами JavaScript, вторую – при записи в бинарник.

Например, используем эти таблички для base64 кодирования/декодирования бинарных данных (методы из emmet-app.js)

/**
 * @author Sergey Chikuyonok (serge.che@gmail.com)
 * @link http://chikuyonok.ru
 */
emmet.define('base64', function(require, _) {
	var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
 
	return {
		/**
		 * Encodes data using base64 algorithm
		 * @author Tyler Akins (http://rumkin.com)
		 * @param {String} input
		 * @returns {String}
		 * @memberOf emmet.base64
		 */
		encode : function(input) {
			var output = [];
			var chr1, chr2, chr3, enc1, enc2, enc3, enc4, cdp1, cdp2, cdp3;
			var i = 0, il = input.length, b64 = chars;
 
			while (i < il) {
 
				// call .asciiCodeAt() instead of .charCodeAt()
				// see AkelEmmet.js in Scripts folder for details
				cdp1 = input.asciiCodeAt(i++);
				cdp2 = input.asciiCodeAt(i++);
				cdp3 = input.asciiCodeAt(i++);
 
				chr1 = cdp1 & 0xff;
				chr2 = cdp2 & 0xff;
				chr3 = cdp3 & 0xff;
 
				enc1 = chr1 >> 2;
				enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
				enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
				enc4 = chr3 & 63;
 
				if (isNaN(cdp2)) {
					enc3 = enc4 = 64;
				} else if (isNaN(cdp3)) {
					enc4 = 64;
				}
 
				output.push(b64.charAt(enc1) + b64.charAt(enc2) + b64.charAt(enc3) + b64.charAt(enc4));
			}
 
			return output.join('');
		},
 
		/**
		 * Decodes string using MIME base64 algorithm
		 * 
		 * @author Tyler Akins (http://rumkin.com)
		 * @param {String} data
		 * @return {String}
		 */
		decode : function(data) {
			var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, tmpArr = [];
			var b64 = chars, il = data.length;
 
			if (!data) {
				return data;
			}
 
			data += '';
 
			do { // unpack four hexets into three octets using index points in b64
				h1 = b64.indexOf(data.charAt(i++));
				h2 = b64.indexOf(data.charAt(i++));
				h3 = b64.indexOf(data.charAt(i++));
				h4 = b64.indexOf(data.charAt(i++));
 
				bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
 
				o1 = bits >> 16 & 0xff;
				o2 = bits >> 8 & 0xff;
				o3 = bits & 0xff;
 
				if (h3 == 64) {
					tmpArr[ac++] = String.fromAsciiCode(o1); // String.fromCharCode(o1);
				} else if (h4 == 64) {
					tmpArr[ac++] = String.fromAsciiCode(o1, o2); //String.fromCharCode(o1, o2);
				} else {
					tmpArr[ac++] = String.fromAsciiCode(o1, o2, o3); //String.fromCharCode(o1, o2, o3);
				}
			} while (i < il);
 
			return tmpArr.join('');
		}
	};
});

Крепкого Вам чая в бокале, сладкого лимона и главное конечно, я знаю, что банален, но желаю хорошего настроения. От чего оно зависит?

nginx+php-fpm под Windows

Здравствуйте!

nginx

Apache – король веб-серверов, если можно так сказать. Но на пятки ему наступает даже не IIS от Microsoft, не lighttpd, а nginx (произносится как Энджин-Икс, engine с английского мотор, двигатель) нашего соотечественника Сысоева.

Чем он хорош? Говорят, что статика отдаётся гораздо быстрее, чем у Апача, да и динамика я думаю тоже. Он жрёт меньше ресурсов, что может быть критически важно для нагруженных серверов. Раньше мнгоие применял связку nginx+Apache – nginx для отдачи статики (рисунков, js/css etc.), а Апач – для отдачи динамики (PHP/Perl/Python/Ruby etc.). Но теперь nginx можно применять без Апача, так как для него появилось куча плагинов и дополнений, поэтому вместо связки nginx+Apache+PHP (мы тут говорим о PHP-среде) легко настроить просто nginx+php-fpm. Ладно, об нём написано куча литературы, не буду повторяться, опишу лишь процесс установки nginx+php-fpm под Виндовс (Windows).

Хотя, конечно, nginx органичней всего чувствует себя в FreeBSD и Linux (любой Unix-среде, наверное), под Винду он тоже неплохо работает, по крайней мере я его у себя на домашнем компе установил, чтобы тестировать некоторые штуки.

Итак, процесс установки/первичной настройки. Этот процесс расписан здесь: http://nginx.org/ru/docs/windows.html
я приведу лишь выжимку.

Смотрим доступные версии nginx под windows здесь: http://nginx.org/en/download.html
Сейчас есть версия 1.8.0, несколько месяцев назад я устанавливал 1.6.2, которая и сейчас у меня работает.
Итак, скачиваем текущую версию под windows: http://nginx.org/download/nginx-1.8.0.zip

Для удобства примем то, что я пользую сейчас:
Создаём папку C:\usr. Заходим в неё и распаковываем nginx-1.8.0.zip здесь (это можно проделать через GUI-интерфэйс).
Затем запускам териминал и заходим:

> C:
> cd C:\usr\nginx-1.8.0
> start nginx

Тут Виньда может выкинуть окошко с предупреждением (см. скриншот), что nginx пытается получить доступ в сеть. Мы конечно же разрешаем.

allow nginx to network

Проверяем, запущен ли nginx и видим результат:

>tasklist /fi "imagename eq nginx.exe"
 
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
nginx.exe                     1336 Console                    1      6,440 K
nginx.exe                     3136 Console                    1      6,268 K
nginx.exe                     4864 Console                    1      6,496 K
nginx.exe                     6544 Console                    1      5,872 K

Остановим nginx нормально: nginx -s quit. Есть ещё несколько полезных команд для nginx:
nginx -s stop – останов nginx в любом случае (применяется, если nginx -s quit не сработает).
nginx -s reload – перезагрузка .conf файлов (конфигурации)
nginx -s reopen – переоткрытие .log файлов (полезна, если мы удалили или переместили логи при работающем nginx).

Итак, мы остановили nginx сейчас, так как прежде чем его запускать, надо правильно настроить .conf файлы. Они расположены в папке conf. Стандартный файл настройки – nginx.conf, из него директивой include могут подсоединяться другие файлы из этой (впрочем, и из любой другой) папки.
Например, директива include mime.types; в секции http присоединит файл mime.types, в котором находится определения всех стандартных MIME-типов. Впрочем, сам конфиг я обсуждать здесь не буду, о нем много написано в инете, приведу лишь пример своего конфига с краткими пояснениями.

Предупреждение: это конфиг для моей домашней тестовой среды. Для рабочего сервера требуется более тонкая настройка.

worker_processes  1;

error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    
    #
    # Формат лога делаем как у Апача
    #
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;

    # sendfile        on;
    #tcp_nopush     on;
  
    keepalive_timeout  65;

    # Сжатие gzip на лету
    gzip  on;

    server {
        # listen       801;
        server_name  localhost;
				autoindex on; # allow dir listing
				root E:/sites;
				
        #charset koi8-r;
        #access_log  logs/host.access.log  main;

	#
        # запретим доступ ко всем файлам, начинающимся с точки 
	#
        location ~ /\. {
            deny  all;
        }

        location / {
            root   E:/sites;
            index  index.html index.htm index.php;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

	#
        # передаем все PHP скрипты серверу FastCGI, слушающему на 127.0.0.1:9123
        #
        location ~ \.php$ {
            root           E:/sites;
            fastcgi_pass   127.0.0.1:9123;
            fastcgi_index  index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
}

Итак, в этом конфиге большинство настроек оставлено по умолчанию, а корень сайтов у нас в E:\sites, что в первую очередь делает команда root E:/sites. Обратите внимание на прямые слэши в стиле Unix в пути к папкам и файлам – это требование nginx, даже для Windows-версии.

Теперь можно запускать nginx (start nginx), если мы его останавливали перед этим, либо применить команду nginx -s reload, чтобы сервер перечитал конфиги без остановки своей работы, что полезно при работающем внешнем сайте.

Итак, теперь надо настроить PHP-FPM для Windows. Учтите, что мы уже в нашем конфиге сделали его поддержку на порту 9123 (под-секция location ~ \.php$)

PHP-FPM для Windows

1. Скачиваем свежий (или версию по выбору) .zip-архивчик с http://windows.php.net/download/. Архивчик должен быть VC11/VC9, что содержит в себе FastCGI-файл (phpcgi.exe).
2. Создаем папку в C:\usr, например с именем php-5.6.9 и распаковываем в неё содержимое архива.
3. Редактируем файл php.ini в соотв. со своими предпочтениями, единственное, убедиться, что у нас есть такая строка:

# nginx security setting
cgi.fix_pathinfo=0

Она закрывает одну из старых уязвимостей nginx. Далее можно подключить PHP-модули по вкусу, расскоментировав их в соотв. секции и произвести другие настройки.

4. Теперь создадим .bat-файл, например php-fpm-start.bat с таким содержимым:

@echo off
echo Starting PHP FastCGI...
set path=c:\usr\php-5.6.9;%PATH%
C:\usr\php-5.6.9\php-cgi.exe -b 127.0.0.1:9123 -c C:\usr\php-5.6.9\php.ini

и запустим его. Если мы его запускаем из GUI, то появится окно консоли и останется открытым, придётся с этим смириться.

Всё, наш сервер мы уже давно настроили на соединение с этим PHP процессом.

Для проверки создаём файл index.php в папке E:\sites с таким содержимым:

<?php
phpinfo();

Теперь направляем наш любимый браузер на http://localhost и видим такую примерно картину:

phpinfo() начало

phpinfo

phpinfo() с версией nginx

phpinfo nginx

Здесь же можно посмортеь переменные среды и подключаемые модули. Для совместимости nginx создет переменные среды, совместимые с апачевскими, например _SERVER[“SERVER_NAME”], _SERVER[“DOCUMENT_ROOT”], _SERVER[“REQUEST_URI”], _SERVER[“SCRIPT_NAME”] и т.д., и мы можем использовать их в своих PHP-сценариях, как делали это в случае с Апачем.

До свидания!

Моя статья в Хакер “Заморозь своего пингвина”

Предисловие

Здравствуйте.
Почти 8 лет назад в журнале Хакер 2007 года за сентябрь (№105) была опубликована моя статья. Как она создавалась? Я уже сейчас не помню точно, помню только, что я увлекался Линуксом тогда и мне понравился Suspend2 (ныне TuxOnIce), я настроил его у себя в Gentoo и у меня всё получилось. Это было круто и я захотел поделиться с сообществом по теме. моим любимым журналом тогда был “Хакер” (сейчас – LinuxFormat), там был раздел Unixoid. Я связался с редактором раздела, объяснил ему тему, он мне ответил что в принципе тема неплоха, давай попробуем. Объяснил условия, формат статьи и её объем максимальный. Что в итоге – я всё сделал по их стандартам (журнала Хакер), выслал им архивчик, и моя статья была опубликована в Хакере №9 (105) от 2007 года – https://xakep.ru/issues/xa/105

Статья

Статья назвается “Заморозь своего пингвина – отправляем Линукс в спячку”. Правда почему-то рядом с моим именем красовлось какое-то имя Goabruce (написано было GOABRUCE & BEOM BEOTIGER). Я написал редактору, что за goabruce и как он тут оказался, ведь статью писал и компоновал всё в ней я один (редактор только её урезал). Он ответил, мол, извините ошибка вышла. Это просто фантастика. За всё время чтения журнала Хакер я такого больше не встречал. Ну да ладно, Бог с этим goabruce’ом, кто бы он ни был. Может он и правда во сне помогал мне делать эту статью.

Буду краток как никогда. В статье рассказывалось о новом методе погружения Линукса в сон (hibernation), названным автором Suspend2. Суть его в том, что текущая RAM системы записывается на диск (в файл или раздел подкачки), и компьютер выключается/перезагружается, а при повторном входе в систему память полностью восстанавливается как есть с диска – и всё текущее окружение становится доступным сразу. то есть все открытые программы, процессы, окна и т.п. при таком входе в систему остаются на месте, и ты можешь продолжить работу как есть, как будто компьютер вовсе не выключался на ночь (или день, смотря кто когда работает).

Круто? Да, круто. Удобно? Несомненно. Да просто супер!

Сегодня

Итак, после большого перерыва, когда я пользовался Linux’ом только время от времени (в виртуальных машинах), с 2008 по 2015 год, когда я поставил себе сначала Kubuntu, потом снес её и установил Linux Mint, чему несказанно рад сейчас, мне на глаза попалась эта моя старая позабытая сейчас уже статья. Ради интереса я подумал, а что там с Suspend2 – заглянул на сайт http://www.suspend2.net, бывший визитной карточкой проекта, а там реклама – он на продажу!

Я подумал, проект загнулся, автор утратил к нему интерес, как часто бывает с открытыми проектами, не приносящими прибыль, потом на глаза мне попалось словосочетание TuxOnIce. Пингвин на Льду? Правильнее было бы назвать – TuxInIce – пингвин во льду. поиск tuxonice в гугле вывел на страничку, до боли знакомую – http://tuxonice.nigelcunningham.com.au Так вот же он, мой родной suspend2! Для прикола я решил попробовать, получится ли у меня поставить его на свой Mint, только без перекомпиляции ядра и всеми прочими долгими настройками, что описывались в моей статье.

Сделал по инструкции на сайте – у них есть прекомплированная версия для Ubuntu (а Mint 100% совместим с Юбунту, по крайней мере так я прочитал в руководстве по Минту), устанавливаемая через PPA – крутая штука, из-за которой я променял Деби на Убунту, а потом Убунту на Минт. Здесь – https://launchpad.net/~tuxonice/+archive/ubuntu/ppa

Просто apt install linux-generic-tuxonice tuxonice-userui, потом выполнил команду “sudo pm-hibernate” и … ничего. Блин, обидно, не работает. Ещё на каком то источнике по теме я прочитал слово “reboot”, перезагрузился, попробовал снова sudo pm-hibernate и всё заработало. Линукс мой ушел в спячку, а потом вернулся волшебным образом. И сейчас я пользуюсь TuxOnIce без проблем (где-то с месяц наверное, правда у меня раздел подкачки около 4 гигов против 8 гигов RAM, как бы это проблем не вызвало, если память будет моя загружена достаточно – а разбираться с подменой образа честно лень пока).

Сама статья

А в качестве бонуса я публикую здесь свою как есть, без купюр, тем более тот номер Хакера от 2007 года/сентябрь давно доступен для скачивания бесплатно с сайта xakep.ru – https://xakep.ru/issues/?y=2007

Скачать оригинал статьи от 2007 года вместе с рабочими материалами и скриншотами можно здесь: http://beotiger.com/download/xakep_article2007

Заморозь своего пингвина.

Предыстория.

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

В этом случае на помощь придёт Suspend2 (http://www.suspend2.net). Почему именно он? Во-первых, это активно развивающийся и успешный проект Найджэла Канингхэма (Nigel Cunningham), Бернарда Блэкхэма (Bernard Blackham), Флоренца Шобо (Florent Chabaud) и многих других, который в своё время отделился от swsusp и сейчас развивается независимо. Во-вторых, он обладает вкусностями, мимо которых не может пройти ни один заядлый линуксоид, да и просто любитель компьютеров. Вот основные из них:

  • Динамическая и быстрая компрессия образа памяти (по умолчанию используется метод LZF).
  • Полная поддержка асинхронного или предупреждающего чтения-записи
  • Поддержка любого количества своп-разделов или файлов.
  • Возможность безопасно прервать процесс засыпания нажатием клавиши ESC.
  • Возможность записи полного образа памяти
  • Поддержка сжатия и кодирования записываемого образа.
  • Доброжелательный графический интерфейс.
  • Поддержка больших объёмов памяти (на настоящий момент – вплоть до 4 Гигабайт), многопроцессорных систем.
  • Поддержка скриптов.
  • Может быть полноценной заменой стандартному swsusp.

Если вкратце, то Suspend2 сохраняет содержимое RAM компьютера и выключает питание. При последующем включении он восстанавливает содержимое RAM, и вы можете продолжать работу как ни в чём не бывало – нет необходимости снова запускать программы, открывать документы, терминалы и т.д. и т.п.

Что нужно для успешной установки и работы Suspend2? В принципе, если у вас современный компьютер на базе процессора Pentuim и IDE диски, а так же свежее ядро ветки 2.6, то с большой вероятностью Suspend2 будет работать без проблем. В частности, для корректной работы необходима поддержка процессором pse или pse36 (page size extensions).

Проверяем:

$ cat /proc/cpuinfo | grep flags

flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe cid xtpr

В данном случае процессор (а это относительно старенький Celeron 2ГГц), имеет поддержку и того, и другого.

Скриншот 1: Основная страница проекта Suspend2.

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

Готовим ядро.

Да. Если вы никогда раньше не компилировали ядро своему любимому Пингвину… что ж, самое время сделать это сейчас. Как говорится, всё всегда когда-нибудь бывает в первый раз. Тем более процедура компиляции ядра не такая сложная и утомительная, как может показаться на первый взгляд. Но, поначалу, конечно, всё будет не так просто. Главное, помните, что не следует сжигать мосты за собой, то есть не удаляйте ваше текущее рабочее ядро из /boot и ссылки на него из загрузчика, пока не убедитесь в течение достаточного времени, что новое ядро, которое вы сами откомпилировали, работает без проблем. Ссылки на статьи по конфигурировании и компиляции ядра в Линуксе вы можете найти во врезке.

Итак, сперва убедитесь, что исходники работающего в данный момент ядра лежат в /usr/src/linux (дефолтовое место для большинства линукс-дистрибутивов).

Смотрим:
$ uname -a
Linux beoplanet 2.6.19.2 #3 Mon May 14 17:09:01 MSD 2007 i686 Intel(R) Celeron(R) CPU 2.00GHz GenuineIntel GNU/Linux
$ file /usr/src/linux
/usr/src/linux: symbolic link to `linux-2.6.19.2'
$ ls /usr/src/linux
arch Documentation ipc Makefile REPORTING-BUGS usr
block drivers Kbuild mm scripts vmlinux
COPYING fs kernel Module.symvers security
CREDITS include lib net sound
crypto init MAINTAINERS README System.map

Здесь мы видим, что у нас рабочее ядрышко 2.6.19.2, а символическая ссылка (/usr/src/linux) указывает на каталог с исходниками именно для этой версии.

Если у вас нет каталога /usr/src/linux, или он пуст, значит, исходники ядра скорее всего просто не установлены в вашей системе. Ничего страшного. Давно пора перейти на свежее ядро, тем более что на каждом диске журнала "Хакер" есть новые ванильные ядра Пингвина. А именно ванильные ядра (то есть истинные, чистые ядра с kernel.org безо всяких патчей, одобренные самим Линусом Торвальдсом) наиболее точно подходят Suspend2! (почему – читайте ниже). Скачиваем свежее ядро с kernel.org, распаковываем его в /usr/src/ и делаем на него симлинк /usr/src/linux.

Обратите внимание на версию ядра. В данный момент на основной странице закачки Suspend2 для версии 2.2.10 предлагаются патчи для следующих версий ядер: 2.6.18.8, 2.6.19.7, 2.6.20.11, 2.6.21.1, 2.6.22-rc1 и ubuntu-feisty.

Для других версий вы можете поискать патчи здесь: http://www.suspend2.net/downloads/all/.

Замечания для владельцев Линукса на базе ядер 2.4. С главной страницы Suspend2 были убраны все ссылки на патчи для этих версий, потому что были сообщения о разрушении файловых систем при их использовании.

Помимо всего прочего, если вы пользователь Gentoo/GNU Linux, то для вас уже есть пропатченные ядра. Просто выполняем команду:
# emerge suspend2-sources

и патчить ядро нам уже не нужно (то есть можно сразу переходить к настройке и компиляции ядра).

Для пользователей последних версий Fedora Core и Red Hat так же есть готовое решение:
# yum install kernel-suspend2

В этом случае штатный инсталлятор всё сделает за вас – вам надо будет только перезагрузиться и использовать hibernate.

Накладываем патч.

Скриншот 2: Страница для закачки патчей и скриптов.

Итак, мы убедились, что у нас установлены исходники рабочего ядра. Если вы используете новое ядро, сначала убедитесь в его работоспособности (отконфигурируйте, откомпилируйте, установите его и загрузитесь с него).

Пришло время наложить патч Suspend2. Идём на http://www.suspend2.net/downloads, выбираем подходящий под нашу версию ядра патч, скачиваем его, например, в нашем случае для версии 2.6.19.2 скачиваем suspend2-2.2.9-for-2.6.19.patch.bz2. В общем случае, ядра версий 2.6.X.Y не слишком отличаются от версий 2.6.X, поэтому возможно использование одного и того же патча.

# wget http://www.suspend2.net/downloads/all/suspend2-2.2.9-for-2.6.19.patch.bz2 -P /tmp
Командуем:
# cd /usr/src/linux
# bzcat /tmp/suspend2-2.2.9-for-2.6.19.patch.bz2 | patch -p1
(путь и версия патча в вашем случае могут быть другими).

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

Компилируем ядро.

Теперь делаем make menuconfig, загружаем нашу текущую рабочую конфигурацию и приступаем к настройке поддержки Suspend2 в ядре.

Сперва убедимся, что включён Prompt for development and/or incomplete code/drivers в секции Code Maturity, включающий некоторые тестовые опции в конфигурировании ядра. Затем заходим в секцию Power management options (ACPI, APM) и видим там новый пункт Suspend2. Отмечаем его, и тут же заходим в подменю.

Здесь нужно сделать паузу и решить, что мы будем использовать в качестве буфера – специальный файл на жёстком диске или раздел подкачки. За это отвечают две опции: File Allocator и Swap Allocator. В принципе, можно отметить оба пункта, и решать откуда грузиться, непосредственно в самом загрузчике (см. далее). Но должен быть отмечен хотя бы один пункт! Другие опции можно оставить как есть, но, забегая вперёд, скажу, что если при восстановлении со свопа в загрузчике вы не хотите указывать девайс свопа, можно сделать это здесь, в пункте Default resume device name задав имя свопа, например, так: swap:/dev/hdb4, где /dev/hdb4 и есть раздел файла подкачки (в вашем случае он, скорее всего, будет другим).

Теперь идём в раздел Cryptographic options, находим пункт LZF compression algorithm и включаем его. Заметьте, что он должен быть встроен непосредственно в ядро, а не включен в виде модуля, иначе сжатие не будет работать.

Также, если у вас карточка от Nvidia на шине AGP, и вы не хотите при пробуждении лицезреть тёмный экран, необходимо в ядре отключить agpgart – поддержку AGP, включённую по умолчанию, тем более что у драйверов от Nvidia есть своя поддержка этой шины. Итак, заходим в секцию Device Drivers, подсекцию Character devices, там находим пункт /dev/agpgart (AGP Support) и выключаем его.

Скриншот 3: Конфигурируем ядро.

Если эта версия ядра не использует Initrd/Initramfs, то здесь можно сохраняться и компилировать своё ядро:

#make && make modules_install

и переходить к следующему пункту.

Если же вы используете Initrd/Initramfs, то вам надо будет вручную включить пробуждение: или модифицировать создание initrd/ramfs вашего дистро, или изменить скрипт linuxrc или init, включив туда следующую строчку:

echo 1 > /sys/power/suspend2/do_resume

ВАЖНО: эта строчка должна идти ПЕРЕД тем, как initrd/ramfs монтирует файловую систему! Если этой строчки нет, пробуждение не будет возможным, если же эта строчка идёт ПОСЛЕ монтирования файловой системы, она (файловая система) может быть разрушена! Помните об этом, и будьте осторожны.

Чтобы получить дополнительную информацию об initrd почитайте Documentation/initrd.txt (из каталога исходников ядра).

Предварительная настройка Suspend2

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

Управлять Suspend2 можно через виртуальный каталог /sys/power/suspend2, составляя свои скрипты для пробуждения/восстановления системы, но удобнее всё же будет воспользоваться готовым решением – hibernate-скриптом, который всю работу будет делать за нас.

Скачиваем hibernate-скрипт и устанавливаем его:

#wget http://www.suspend2.net/downloads/all/hibernate-script-1.95.tar.gz -P /tmp
#tar xzf /tmp/hibernate-script-1.95.tar.gz
#cd /tmp/hibernate-script-1.95
#./install.sh

Сам скрипт по умолчанию инсталлируется в /usr/sbin (это можно изменить в install.sh), а конфигурационные файлы (их может быть несколько) инсталлируются в каталог /etc/hibernate/.

Для пользователей Gentoo и Debian дистрибутивов уже есть включённый в их дистрибутивы hibernate-script.

В случае Gentoo делаем

#emerge hibernate-script

А в Debian (и ему подобных) что-то типа этого:

#apt-get install hibernate

По умолчанию настройки Suspend2 разбиты на три файла конфигураций: hibernate.conf, suspend2.conf и common.conf. В принципе, никто не мешает нам собрать их все в один главный файл (hibernate.conf), но мы пойдём по пути наименьшего сопротивления 😉 .

Начнём с первого и отредактируем файл /etc/hibernate/hibernate.conf

#vim /etc/hibernate/hibernate.conf

TryMethod suspend2.conf
#TryMethod disk.conf
#TryMethod ram.conf

Так как мы используем Suspend2, оставляем только его, disk.conf и ram.conf нам не понадобятся.

Дальше смотрим файл /etc/hibernate/suspend2.conf

#vim /etc/hibernate/suspend2.conf

UseSuspend2 yes
Reboot no
EnableEscape yes
DefaultConsoleLevel 1
Compressor lzf
Encryptor none

Include common.conf

Здесь находятся общие для Suspend2 настройки. Перечислю лишь основные из них.

Первая строчка UseSuspend2 yes говорит, что мы собираемся использовать именно Suspend2 (а иначе зачем мы вообще патчили наше ядрышко? 😉 )

Опция Reboot решает, хотим ли мы перезагружаться сразу после заморозки.
Опция EnableEscape yes позволит нам отменить процесс заморозки нажатием клавиши ESC.
Опция DefaultConsoleLevel 1определяет вид отображения при заморозке и разморозке (0 – простой прогресс-бар, 1 – прогресс-бар с процентами, 2 и выше выдаёт обильную отладочную информацию о происходящем).
Опции Compressor и Encryptor определяют методы сжатия и шифрования образа. Их имена можно узнать, выполнив команду #cat /proc/crypto.

Остальные настройки здесь вы можете править по вкусу или оставить их как есть, подробную информацию о них вы можете узнать из man(5)hibernate.conf:

$ man 5 hibernate.conf

Теперь переходим к основным настройкам, собранным в файле /etc/hibernate/common.conf:

Подробнее остановлюсь на, пожалуй, самых важных из них, остальные вы так же можете изменить по вкусу, сверяясь с man(5)hibernate.conf.

# vim /etc/hibernate/common.conf

UnmountFSTypes – здесь можно перечислить типы файловых систем, которые нужно размонтировать перед заморозкой, например, UnmountFSTypes smbfs nfs ntfs vfat. Смотрите ниже, раздел Подводные камни, зачем это может понадобиться. В принципе, если у вас есть чётко заданные устройства, можно размонтировать их в пункте Unmount (например, Unmount /media/winC /media/MyHomeNetwork)

Их же можно смонтировать обратно при пробуждении в пункте Mount (Mount /media/winC /media/MyHomeNetwork), иначе при пробуждении Suspend2 не сделает это автоматически.

Пункт UnloadModules позволяет перечислить модули, которые обязательно надо выгрузить перед заморозкой, но можно воспользоваться пунктами UnloadAllModules yes для выгрузки всех модулей, или UnloadBlacklistedModules yes для выгрузки тех модулей,чьи имена перечислены в файле /etc/hibernate/blacklisted-modules. Пункт LoadModules позволяет задать имена модулей, загружаемых при пробуждении (LoadModules auto автоматически загрузит все модули, которые были выгружены).

В пункте DownInterfaces можно указать сетевые интерфейсы, которые надо будет отключить перед засыпанием, а UpInterfaces auto автоматически запустит все остановленные интерфейсы при пробуждении.

Пункт RestartServices позволяет останавливать/запускать перечисленные здесь службы. Имена служб должны соответствовать названиям скриптов в каталоге init.d и быть активными на данном уровне запуска (runlevel).

SwitchToTextMode позволяет во время засыпания переключаться в текстовый режим, а при пробуждении возвращаться обратно к X'ам. Это может быть полезно, если BIOS при пробуждении не восстанавливает ваш графический адаптер, и ядро не может его опознать.

Опция UseDummyXServer также может помочь в ряде случаев, когда, например, при пробуждении на некоторых видеокартах наблюдается потеря ускорения в 3D графике.

Параметрами в IncompatiblePrograms вы можете указать программы, которые по каким либо причинам не совместимы с Suspend2, в этом случае, если Suspend2 обнаружит, что такая программа выполняется в настоящий момент времени, он отменит заморозку.

Также можно запереть вход в систему после пробуждения, одним из параметров в опциях LockConsoleAs, LockXScreenSaver, LockGnomeScreenSaver, LockKDE, LockXLock, LockXAutoLock (в таком случае правильным будет определить лишь один из вышеперечисленных параметров). Если вы это сделаете, то после пробуждения необходимо будет вновь залогиниться, чтобы продолжать работать.

Наконец, если в опции XStatus вы укажете одно из значений (kde, gnome или x), то Suspend2 будет выводить прогресс-бар при засыпании/пробуждении, а также выдавать сообщения об ошибках в окошках для указанной графической среды.

Скриншот 4: Настраиваем конфиг.

Итак, мы закончили настройку Suspend2 и можно уже переходить в настройке загрузчика и перезагрузки в Suspend2. Но если вы решили использовать не раздел подкачки, а файл в качестве буфера для сохранения RAM, то его сперва необходимо подготовить. Делается это так:

В /etc/hibernate/suspend2.conf ищем строку FilewriterLocation, раскомментируем её и переделываем по своему вкусу, например, так:

FilewriterLocation /var/suspend_file 1024

Здесь первый параметр – это имя файла под буфер, второй – его размер в мегабайтах. Обычно его размер можно указывать равным объёму оперативки вашего бокса – не забудьте, что Suspend2 сжимает сохранённый образ RAM!

Теперь командуем:

#hibernate –no-suspend

и Suspend2 сам подготовит для нас файл. Смотрим, что выдаёт /sys/power/suspend2/resume2

#cat /sys/power/suspend2/resume2

Это может быть что-то типа file:/dev/hda1:0x10011f. Записываем или запоминаем эту строчку – она нам позже понадобится при конфигурировании загрузчика.

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

В файле /etc/hibernate/suspend2.conf находим и заполняем следующий пункт:

SuspendDevice swap:/dev/hda3/swap_file

Запускаем:

# hibernate –no-suspend.

Смотрим:

# cat /sys/power/suspend2/swap/headerlocations

Мы можем получить что-то типа swap:/dev/hda3:0xfd400. Также записываем или запоминаем эту строчку и сперва укажем её в /etc/hibernate/suspend2.conf:

SuspendDevice swap:/dev/hda3:0xfd400

В случае изменения местоположения файла подкачки, или если вы его удалили, а потом вновь восстановили, вам необходимо будет вновь свериться с /sys/power/suspend2/swap/headerlocations, чтобы узнать его новые координаты (для файлов Suspend2 запоминает абсолютное расположение их на жёстком диске).

Эти новые координаты необходимо будет прописать в конфиге и в загрузчике (смотрите ниже).

Настройка загрузчика

Итак, мы откомпилировали ядро и поместили его в /boot, например так: cp arch/i386/boot/bzImage /boot/kernel-2.6.19.2suspend2 (имя по вашему желанию).

Теперь указываем на него в загрузчике в опции kernel, и добавляем туда строчку resume2=указание на ваш буфер (своп или файл).

Если вы используете своп, это может выглядеть так: resume2=swap:/dev/hdb4

Если же вы решили использовать файл, сюда надо подставить значение из /sys/power/suspend2/resume2 с префиксом file:, то есть это может выглядеть так: resume2=file:/dev/hda1:0x10011f.

Если это своп-файл, то строчка может выглядеть так: resume2=swap:/dev/hda3:0xfd400

Вся секция (в случае использовании свопа на /dev/hdb4) может выглядеть так (при использовании grub):

title Wake UP! (Gentoo Linux – kernel 2.6.19.2 with Suspend2)
root (hd0,0)
kernel /boot/kernel-2.6.19.2suspend2 root=/dev/hdb1 init=/sbin/init quiet resume2=swap:/dev/hdb4

В вашем случае имена разделов и образа ядра могут быть другими.

В lilo это же надо указывать примерно так:

image = /boot/ kernel-2.6.19.2suspend2
label = Wake UP! (Gentoo Linux – kernel 2.6.19.2 with Suspend2)
append = "resume2=swap:/dev/hdb4"

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

Такая секция может выглядеть, например, так (опять же, если мы используем grub в качестве загрузчика):

title Boot without resume (Gentoo Linux – kernel 2.6.19.2 with Suspend2)
root (hd0,0)
kernel /boot/kernel-2.6.19.2suspend2 root=/dev/hdb1 init=/sbin/init quiet resume2=swap:/dev/hdb4 noresume2

Для lilo:
image = /boot/ kernel-2.6.19.2suspend2
label = Wake UP! (Gentoo Linux – kernel 2.6.19.2 with Suspend2)
append = "resume2=swap:/dev/hdb4 noresume2"
append = "noresume2"

Не забудьте, если вы используете lilo, каждый раз после изменения lilo.conf презапускать lilo:
#/sbin/lilo

Теперь вы всегда сможете загрузить систему без пробуждения, выбрав строчку Boot without resume.

Итак, у нас всё готово. Но сперва необходимо убедиться, что мы всё сделали верно, и можем использовать Suspend2. Для этого сначала необходимо просто перезагрузиться в новом ядрышке (если вы сделали два пункта – без noresume2 и с ним, как мы советовали, можно выбрать любой из них – Suspend2 сам распознаёт готовность системы к пробуждению), и смотрим лог ядра:

$ dmesg | grep Suspend2

Suspend2 Core.
Suspend2 Userspace UI Support module loaded.
Suspend2 Checksumming module loaded.
Suspend2 Userspace Storage Manager module loaded.
Suspend2 Compressor module loaded.
Suspend2 Encryptor module loaded.
Suspend2 Block I/O module loaded.
Suspend2 Swap Allocator module loaded.
Suspend2 2.2.9: SwapAllocator: Signature found.
Suspend2 2.2.9: Resuming enabled.
Suspend2 2.2.9: Normal swapspace found.
Suspend2 2.2.9: No image found.

Обратите внимание на строчку Suspend2 2.2.9: Resuming enabled. Она показывает, что наш пингвин готов к заморозке/разморозке! Несмотря на это, впервые для апробирования этой фичи рекомендуется усыпить систему без X'ов.

Переходим на текстовую виртуальную консоль (Alt+Ctrl+F1) , закрываем X'ы, например, так

# /etc/init.d/xdm stop (или # init 3, если у вас Red Hat, Fedora или Mandrake)

и делаем:

#hibernate

Если засыпания не состоялось (например, Suspend2 не смог выгрузить модуль – а он сообщит об этом на экране или в логе (по умолчанию в /var/log/hibernate.log), можно форсировать процесс:

#hibernate –force

и Suspend2 должен сделать свою работу в любом случае.

Скриншот 5: Примерно так может происходить процесс засыпания.

Если же Suspend2 повис, смотрим его логи – это может быть, например, из-за несовместимого модуля, который мы забыли выгрузить – перезагружаемся, включаем его название в выгружаемые модули (в файле конфигурации hibernate) и повторяем попытку.

Теперь включаем компьютер опять (если у нас в опции Reboot стояло no), выбираем в загрузчике пункт Wake UP! (Gentoo Linux – kernel 2.6.19.2 with Suspend2), и через небольшой промежуток времени (если всё пошло по плану, конечно) мы оказываемся в той консоли, откуда ушли, с сохранением всего рабочего окружения!

Стартуем X'ы (/etc/init.d/xdm start или init 5), открываем консоль и пробуем заснуть отсюда:
$ su
# hibernate

Потрясены?? Я вас понимаю. Да, Suspend2 работает очень быстро. Например, на засыпание при полной графической среде KDE (у меня система на Celeron-2GHz с 512 метрами RAM и обычными ATA-дисками с разделом подкачки на 512 мегабайт, дешёвый графический адаптер Nvidia MX-440BX с последней версией legacy-драйвера от Nvidia (1.0-9631-pkg1) я трачу около 30 секунд, а на просыпание – 22 секунды! С восстановлением, естественно, полного рабочего окружения KDE, открытых окон с загруженными документами и тому подобное.