1  2   

/dev во freebsd chroot

2 марта 2017, 12:59
Не нашёл в интернете хорошего решения, поэтому выкладываю тут.

Т.к. во FreeBSD нельзя сделать просто mknod в произвольном месте фс (вернее можно, но результат работать не будет с ошибкой "operation not supported"), то для доступа к устройствам внутри chroot приходится немного шаманить - а именно монтировать devfs с нужными нам устройствами.

Покажу на примере php-fpm. Создаём файл /usr/local/etc/rc.conf.d/php_fpm со следующим содержимым:
mount_devs() {
for i in $php_fpm_chroots; do
umount "${i}/dev" 2>/dev/null || true
devfs_domount "${i}/dev" devfsrules_hide_all
devfs -m "${i}/dev" rule apply path null unhide
devfs -m "${i}/dev" rule apply path random unhide
devfs -m "${i}/dev" rule apply path urandom unhide
done
}

start_precmd="$start_precmd && mount_devs"

и в rc.conf дописываем:
php_fpm_chroots="/var/www1 /var/www2"

Создаём по нужным путям dev/, делаем рестарт сервиса - и после этого всё должно заработать.
Комментировать Теги: #nix  

https

1 февраля 2017, 15:34
В связи с наметившейся тенденцией всяческого ущемления (понижение позиции в выдаче поисковиков, предупреждения о небезопасности в браузерах) сайтов, доступных только по http, а так же по причине необходимости повышения безопасности передаваемых данных, передо мной возникла задача внедрения https с минимальными материально-техническими затратами на внедрение и сопровождение.

Итак, возможны несколько подходов при внедрении https.
1. Использование самоподписанных сертификатов. Этот подход хорошо подходит для небольших частных сайтов, различных админок и подобной мелочи.
Плюсы такого подхода:
+ Ни от кого не зависим - сертификат можно самостоятельно сделать на любой домен, на любой срок. Обычный центр сертификации по очевидным причинам не станет подписывать сертификат для внутренних доменов (*.lan и т.п.).
+ Всё довольно просто - получить самоподписанный сертификат можно буквально в одну команду.
Минусы:
- При первом посещении сайта пользователю будет выдано предупреждение о недоверенном сертификате и необходимо будет добавить сертификат в список доверенных.
Для некоторых утилит часто неясно как или вовсе невозможно это сделать.

howto:
openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365


2. Использование собственного центра сертификации. Оптимальный вариант для внутренних ресурсов организаций. К плюсам и минусам подхода №1 добавляется:
+ Опять же ни от кого не зависим - сертификат можно самостоятельно сделать на любой домен, на любой срок.
+ Централизованное управление выданными/отозванными сертификатами. Как бонусом - удобно мониторить истекающие сертификаты.
+ Для доверия к любому внутреннему ресурсу достаточно добавить всего один сертификат на всех клиентах. При системы центрального управления конфигурациями (active directory, ansible и т.п.) сделать это крайне просто.
- При компрометации сертификата центра сертификации автоматически компрометируются все серверы и клиенты, на которых он установлен. Т.к. x509 не предусматривает ограничений на выдаваемые центром сертификации сертификаты, то компрометируются в том числе и любые https соединения к любым серверам. Единственное что остаётся в безопасности - клиенты, использующие привязку к сертификату (certificate pinning).
- Собственный центр сертификации относительно сложно настроить. Нельзя просто скопировать первый рецепт с serverfault - нужно понимать что и зачем делать.

howto:
Не существует быстрого и универсального пути, но для себя я написал небольшой скрипт, обладающий минимальным функционалам по созданию ЦС, созданию и подписи ключей и сертификатов. Скрипт далеко не идеальный, но длительное время он служил мне верой и правдой.
#!/bin/bash -xe

export OPENSSL_CONF=cnf

a="$1"
shift || true
n="$1"
o="$2"

cd "`dirname $0`"
umask 0007

case "$a" in
gen)
test -n "$n"
openssl genrsa 2048 >private/$n

cp "$OPENSSL_CONF"{,.tmp}
export OPENSSL_CONF="$OPENSSL_CONF.tmp"
echo '[ alt_names ]' >> "$OPENSSL_CONF"
cnt=1
while (( "$#" )); do
echo "DNS.$cnt = $1" >> "$OPENSSL_CONF"
(( cnt++ ))
shift
done

openssl req -new -key private/$n -subj "/C=RU/ST=Belgorod/O=IVTBSU/OU=CA/CN=$n" >csr.$n
openssl req -text -noout <csr.$n
openssl ca -batch -notext -extensions server -in csr.$n >cert/$n
rm csr.$n
;;
genca)
mkdir ca cert private dh || true
openssl genrsa 4096 >ca/key
openssl req -new -key ca/key -subj "/C=RU/ST=Belgorod/O=IVTBSU/OU=CA/CN=ivt.su" >ca/csr
openssl x509 -req -days 10000 -in ca/csr -signkey ca/key >ca/crt
rm ca/csr
echo 100001 >ca/srl
echo 100001 >ca/crlnum
touch ca/index
openssl ca -gencrl >ca/crl
;;
gendh)
test -r cert/$n
openssl dhparam -in cert/$n 1024 >dh/$n
;;
revoke)
test -r cert/$n
openssl ca -revoke cert/$n
openssl ca -gencrl >ca/crl
rm cert/$n private/$n
;;
public)
openssl rsa -in cert/$n -pubout
;;
info)
openssl x509 -in cert/$n -text
;;
chown)
test -n "$o"
for i in dh cert private; do
test -r "$i/$n" || continue
chmod 0400 "$i/$n"
chown $o:wheel "$i/$n"
done
;;
*)
echo "Usage: $0 "
exit 1
;;
esac

Так же понадобится файл конфигурации openssl (cnf):
[ ca ]
default_ca = myca

[ crl_ext ]
# issuerAltName=issuer:copy #this would copy the issuer name to altname
authorityKeyIdentifier = keyid:always

[ myca ]
dir = ./ca
new_certs_dir = $dir
unique_subject = no
certificate = $dir/crt
database = $dir/index
private_key = $dir/key
serial = $dir/srl
default_days = 730
default_md = sha256
policy = myca_policy
x509_extensions = myca_extensions
crlnumber = $dir/crlnum
default_crl_days = 730

[ myca_policy ]
commonName = supplied
stateOrProvinceName = supplied
countryName = optional
emailAddress = optional
organizationName = supplied
organizationalUnitName = optional

[ myca_extensions ]
basicConstraints = CA:false
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
keyUsage = digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
crlDistributionPoints = URI:http://CHANGE.ME/root.crl
nsComment = "OpenSSL Generated Certificate"
subjectAltName = @alt_names


[ req ]
default_md = sha256
distinguished_name = req_distinguished_name
#attributes = req_attributes
x509_extensions = v3_ca
req_extensions = v3_req
[ v3_req ]
subjectAltName = @alt_names
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true

[ req_distinguished_name ]
countryName = Country?
countryName_default = RU
stateOrProvinceName = State?
stateOrProvinceName_default = Belgorod obl.
localityName = City?
localityName_default = Belgorod
0.organizationName = Organization?
0.organizationName_default = Home
commonName = Domain?
commonName_default = change.me
emailAddress = Email?
emailAddress_default = ca@change.me

[ server ]
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = serverAuth
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alt_names

[ client ]
basicConstraints = CA:FALSE
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = clientAuth
keyUsage = digitalSignature


3. Использование публичного центра сертификации. Фактически единственный приемлемый вариант для публичных сайтов.
+ Все клиенты по умолчанию будет доверять вашему сертификату.
- Нужно проходить процедуру верификации для подтверждения владения доменом, при чём домен, очевидно, должен быть публичным.
- Центр сертификации может накладывать собственные ограничения на параметры сертификата. Например, Let's Encrypt выдаёт сертификаты не более чем на ~3 месяца и не допускает использования widcard в доменном имени.
- Большинство центров сертификации хотят денег.

howto:
Я буду использовать let's encrypt (LE) т.к.
1. Он бесплатный;
2. Процедура получения и обновления сертификатов автоматизирована.
Всю грязную работу будет выполнять утилита acme-tiny:
 pkg install acme-tiny

Вряд ли кому-то доставит удовольствие поддерживать сертификаты для нескольких десятков доменов, особенно с учётом срока годности сертификатов LE (~3 месяца). Поэтому я набросал небольшой скрипт. Он автоматически создаёт ключи и сертификаты для указанных доменов и, при близости срока их истекания, проводит обновление.
Предварительная подготовка:
# mkdir -p /var/www/le
# mkdir /etc/ssl/le
# cd /etc/ssl/le
# openssl genrsa 4096 >LE.key

Собственно, сам скрипт:
#!/bin/sh -e

cd "$(dirname $0)"


isok() {
name="$1"; domains="$4"
test -r "$name.key" || return 1
test -r "$name.crt" || return 1
openssl x509 -in "$name.crt" -checkend 2592000 -noout || return 1
f1="`mktemp`"; echo "$domains" |tr : '\n' |sort >"$f1"
f2="`mktemp`"; openssl x509 -in "$name.crt" -text |egrep -m1 '^ +DNS:' |sed -e 's/ *DNS://g' |tr , '\n' |sort >"$f2"
set +e
diff -q "$f1" "$f2" >/dev/null
ret=$?
set -e
rm "$f1" "$f2"
test "$ret" = 0 || return 1
return 0
}

upd() {
name="$1"; group="$2"; service="$3"; domains="$4"
echo "Generating $name..." >&2
cnff="`mktemp`"
test -r "$name.key" || openssl genrsa 4096 >"$name.key"
cat /etc/ssl/openssl.cnf >"$cnff"
echo "$domains" | awk -vRS=: 'BEGIN{printf "[SAN]\nsubjectAltName="}notfirst==1{printf ","}{printf "DNS:"$0; notfirst=1} ' >>"$cnff"
openssl req -new -sha256 -key $name.key -subj "/" -reqexts SAN -config "$cnff" > "$name.csr"
rm "$cnff"
acme_tiny --account-key LE.key --csr "$name.csr" --acme-dir /var/www/le/ > "$name.crt"
rm "$name.csr"
curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem >> "$name.crt"
cat "$name.crt" "$name.key" >"$name.pem"
chgrp "$group" "$name.key" "$name.crt" "$name.pem"
chmod o-rwx "$name.key" "$name.crt" "$name.pem"
test "$service" = '-' || service "$service" reload
}

cat << EOF |grep -v -e^# -e^$ |while read i; do isok $i || upd $i; done

# name group service dns1.example.com:dns2.example.com
web www nginx err200.net:www.err200.net:ftp.err200.net
imap dovecot dovecot imap.err200.net:pop3.err200.net:pop.err200.net
irc ircd inspircd irc.err200.net
EOF


Добавляем в cron:
@monthly /etc/ssl/le/upd.sh


Самое время настроить веб-сервер. Я сделаю это на примере nginx. Let's encrypt верифицирует домен путём загрузки через http файла со случайно сгенерированным именем, нужно это учесть.
Создаём /etc/nginx/lessl.conf:
listen 443 ssl http2;

add_header Strict-Transport-Security "max-age=31536000";

location ^~ /.well-known/acme-challenge/ {
alias /var/www/le/;
try_files $uri =404;
auth_basic off;
}


Теперь в конфиг нужных server'ов просто пишем
include lessl.conf;

... делаем service nginx reload и запускаем скрипт. Если всё сделано правильно - скрипт отрапортует "Certificate signed!" столько раз, сколько в нём указано сертификатов.
Всё, можно прописывать в server'ах:
ssl_certificate /etc/ssl/le/web.crt;
ssl_certificate_key /etc/ssl/le/web.key;

... и сайт должен заработать по https.

При использовании реверс прокси может возникнуть проблема редиректов с https на http внутри сайта. Решается она очень просто:
proxy_redirect default;
proxy_redirect http:// $scheme://;

Или для haproxy:
http-response replace-value Location http://(.*) https://\1 if { dst_port 443 }


На этом всё.
Комментировать Теги: #nix   #web   #https  

...

10 ноября 2016, 16:22
An aircraft company discovered that it was cheaper to fly its planes with less fuel on board. The planes would be lighter and use less fuel and money was saved. On rare occasions however the amount of fuel was insufficient, and the plane would crash. This problem was solved by the engineers of the company by the development of a special OOF (out-of-fuel) mechanism. In emergency cases a passenger was selected and thrown out of the plane. (When necessary, the procedure was repeated.) A large body of theory was developed and many publications were devoted to the problem of properly selecting the victim to be ejected. Should the victim be chosen at random? Or should one choose the heaviest person? Or the oldest? Should passengers pay in order not to be ejected, so that the victim would be the poorest on board? And if for example the heaviest person was chosen, should there be a special exception in case that was the pilot? Should first class passengers be exempted? Now that the OOF mechanism existed, it would be activated every now and then, and eject passengers even when there was no fuel shortage. The engineers are still studying precisely how this malfunction is caused.

Источник

Комментировать Теги: #юмор   #nix  

Применение m4 для генерации конфигурации

5 июня 2016, 17:43
В данной заметке я хочу рассказать о существовании замечательной утилиты - макропроцессора m4.
Заметка носит ознакомительный характер и не ставит целью описание нюансов m4 (RTFM!).

Любой *nix-системный администратор сталкивался с проблемой громоздкости и избыточности конфигурационных файлов. Так, некоторое ПО (php-fpm) не поддерживает наследование секций конфигурации (хотите новый пул в php-fpm, отличающийся лишь директорией и пользователем? будьте добры скопипасьте и все остальные 9000 параметров для нового пула). Другое же ПО (nagios) - несмотря на мощные возможности наследования - имеет довольно громоздкий формат конфигурационных файлов.

Обычно подобные проблемы решают двумя путями: скрипты-генераторы конфигов и системы управления конфигурацией (ansible, puppet). Первый подход мне не нравится своей... неэлегантностью что-ли. О втором же подходе (до некоторой поры) можно сказать - "из пушки по воробьям".

Чем же может помочь m4? m4 - ПО, предназначенное для преобразования входных текстовых данных согласно некоторому набору правил (макросов). Сами макросы могут быть как предопределёнными в m4, так и определяемыми во входных данных (файле конфигурации).

К слову, количество "мусорных" строк в конфигурации Nagios вгоняло меня в уныние с первых дней знакомства с системой. Поэтому, узнав о существовании m4, я решил опробовать этот инструмент именно на Nagios. И результат превзошёл все мои ожидания.
Вот пример старой конфигурации:
define host {
use generic-server
host_name my-server-1234
address 1.2.3.4
}

define service {
use service-ping
host_name my-server-1234
}

define service {
use service-ssh
host_name my-server-1234
_port 2222
}

define service {
use service-tcp
host_name my-server-1234
service_description SSH honeypot
_port 22
}

define service {
use service-users
host_name my-server-1234
}

... и ещё около сотни строк в таком же духе


А вот новая:
add( my-server-1234, 1.2.3.4, (), (
( ping ),
( ssh, _port 2222 ),
( tcp, service_description SSH honeypot, _port 22 ),
( users ),
( procs ),
( mem ),
( load ),
( conns ),
( disk ),
( proc, service_description App servers, _warn 1:1, _crit 1:1, _proc java ),
( filelines, service_description App users, _file /var/db/app/usersdump.txt, _pattern Nobody online, _args -v ),
))


Выгода, как мне кажется, очевидна. На минимальное изучение m4, составление макросов, и переписывание конфигурации Nagios (~100 сервисов) ушло менее одного дня. Более объёмные конфигурации можно переписывать небольшими порциями - весь текст в файле, не являющийся макросами m4, будет скопирован на выход без изменений.

Помимо очевидного плюса (сокращение писанины и копипасты), данный подход имеет парочку неприятных минусов:
  • После редактирования конфигурации необходимо не забывать запускать m4;
  • Некоторые символы и слова требуют специального внимания т.к. могут быть интерпретированы в m4.

На мой взгляд, данные минусы не являются критичными, и m4 заслуживает быть добавленным в арсенал системного администратора.
Комментировать Теги: #nix   #m4   #nagios  

ГОСТ шифр

17 мая 2016, 10:06
В данной статье решается задача создания защищённого соединения с сервером госзакупок с минимизацией необходимости дальнейшей поддержки решения.

1. Ставим OpenSSL версии >= 1.0.1 (с этой версии в основном дереве исходных кодов появилась поддержка ГОСТ), её заголовочные файлы, компилятор.

2. По умолчанию поддержка ГОСТ выключена. Для её включения в начало файла /etc/ssl/openssl.cnf перед первой секцией прописываем:
openssl_conf = openssl_def

[openssl_def]
engines = engine_section

[engine_section]
gost = gost_section

[gost_section]
engine_id = gost
dynamic_path = /usr/lib/x86_64-linux-gnu/openssl-1.0.0/engines/libgost.so
default_algorithms = ALL
CRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet


3. Многие программы (в т.ч. старые версии PHP) не читают конфиг OpenSSL, поэтому их нужно патчить. Т.к. поддерживать патченный PHP довольно накладно, то будем использовать stunnel.

4. stunnel версии 4.55 (последней на момент написания статьи) без патчей тоже не читает конфиг OpenSSL. Распаковываем исходники, патчим их, собираем всё это:
wget http://cryptocom.ru/opensource/stunnel-4.55-cp2.diff
mkdir -p /opt/stunnel-gost/src/
cd /opt/stunnel-gost/src/
tar xzvf ~/stunnel-4.55.tar.gz
patch -p1 <~/stunnel-4.55-cp2.diff
./configure --prefix=/opt/stunnel-gost/
make install


UPD: На момент публикации статьи файл с оригинальным патчем более недоступен по указанной ссылке. Посему выкладываю его здесь:
diff -Nur -X - stunnel-4.55/src/ssl.c stunnel-gost/src/ssl.c
--- stunnel-4.55/src/ssl.c 2012-08-10 01:44:18.000000000 +0400
+++ stunnel-gost/src/ssl.c 2015-08-19 16:01:41.000000000 +0300
@@ -59,6 +59,9 @@
}

int ssl_configure(GLOBAL_OPTIONS *global) { /* configure global SSL settings */
+ OPENSSL_config(NULL);
+ OpenSSL_add_all_algorithms();
+ SSLeay_add_ssl_algorithms();
#ifdef USE_FIPS
if(FIPS_mode()!=global->option.fips) {
RAND_set_rand_method(NULL); /* reset RAND methods */


5. Прописываем в /opt/stunnel-gost/etc/stunnel/stunnel.conf:
foreground = yes
debug = 6
setuid = proxy
setgid = proxy
pid = /tmp/stunnel.pid

socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1

verify = 3
cert = /opt/stunnel-gost/etc/stunnel/clientcert.pem
key = /opt/stunnel-gost/etc/stunnel/clientprivatekey.pem
CAfile = /opt/stunnel-gost/etc/stunnel/servercert.pem

[n1]
client = yes
accept = 1443
connect = int223.zakupki.gov.ru:443
ciphers = GOST2001-GOST89-GOST89
TIMEOUTclose = 0

[n2]
client = yes
accept = 1444
connect = intfz04.lanit.ru:443
ciphers = GOST2001-GOST89-GOST89
TIMEOUTclose = 0


6. Создаём init-файл для upstart (/etc/init/stunnel-gost.conf):
start on runlevel [2345]
stop on runlevel [016]
respawn
respawn limit 10 5
setuid root
setgid root
chdir /opt/stunnel-gost
exec /opt/stunnel-gost/bin/stunnel /opt/stunnel-gost/etc/stunnel/stunnel.conf


Готово. Все запросы на http://127.0.0.1:1443/ будут проксироваться на https://int223.zakupki.gov.ru:443/.
Комментировать Теги: #nix  

Расширение корневого раздела в LVM в RHEL6

24 декабря 2015, 10:23
Вводная: виртуальная машина с одним диском и корневой фс в lvm.
Задача: расширить корневую фс без остановки предоставляемого сервиса.
Решение:
1. Увеличиваем размер диска средствами системы управления виртуальными машинами. В моём случае это Proxmox:
qm resize 100 virtio0 +5G
2. Далее нужно как-то подключить наше новое пространство к VolumeGroup. Вот тут кроется засада. Для RHEL5 можно увеличить размер раздела с PhysicalVolume и обновить таблицу разделов командой partprobe. Но начиная с RHEL6 она покажет шиш и откажется что-либо делать пока мы всё не остановим и не отмонтируем. Однако есть и обходной путь: создаём на этом же диске ещё один раздел с PhysicalVolume чтобы затем расширить нашу VolumeGroup на неё:
parted /dev/vda mkpart primary ext2 НАЧАЛО_РАЗДЕЛА -1
parted set НОМЕР_РАЗДЕЛА lvm on
Затем выполняем потенциально опасную операцию - обновляем наживую таблицу разделов. Существующие разделы при этом остаются на месте (даже если были изменены/удалены), новые же добавляются:
partx -a /dev/vda
3. Дальше дело техники - расширяем VolumeGroup:
vgextend VolGroup /dev/vda3
4. ... расширяем LogicalVolume:
lvextend -l +100%FREE VolGroup/lv_root
5. ... и, наконец, увеличиваем сам раздел:
resize2fs /dev/VolGroup/lv_root
Готово.
Комментировать Теги: #nix  

Удобный поиск и каталогизация файлов в консоли

10 октября 2010, 13:30
Все началось с того, что сегодня утром качалка FatRat сообщила о завершении многонедельной закачки торрента с рипом одного сайта с обоями. Распаковав полторы сотни архивов, удивлению моему предела не было - все 33 тысячи файлов были свалены в одну кучу. О том, чтобы нормально выбрать что-то из нее говорить не приходится. Но зато имена файлов были вполне нормальные, с тегами... так и родился этот простенький скрипт. Он рекурсивно ищет файлы, имя которых содержит заданную фразу и помещает симлинки на эти файлы в отдельную папочку.

#!/bin/bash
# Author: Uzix
# This script create links for all matched files

find_dir='finder.sh'
file_i=0

test -d "$find_dir" && rm -rf "$find_dir"
mkdir "$find_dir"
if [ ! -w "$find_dir" ]; then
echo "Can't open directory ./\"$find_dir\" for writing, trying to use home..."
find_dir="$HOME/finder.sh"
test -d "$find_dir" && rm -rf "$find_dir"
mkdir "$find_dir"
if [ ! -w "$find_dir" ]; then
echo "Can't open home directory for writing, exiting."
exit 1
fi
fi
echo FINDER DIRECTORY IS: "$find_dir"

IFS=$'\n'; for find_file in `find . |grep -i $@`; do
echo FILE: "$find_file"
find_link="$find_dir/$(basename $find_file)"
file_i=0
while test -r "$find_link"; do
((file_i+=1))
file_ext="$(echo $find_file |awk -F . '{print $NF}')"
find_link="$find_dir/$(echo $(basename $find_file $file_ext)\($file_i\).$file_ext)"
done
echo LINK: "$find_link"
ln -s "$(readlink -f $find_file)" "$find_link"
done

PS. Скрипт с башизмом - в POSIX Shell IFS работает по-другому
PPS. Скрипт проверен на именах вроде
Konachan.com - 27833 - horo spice_and_wolf sample_url=http---kuro.hanyuu.net-image-a7fd1e9d564c2a18f3359f4cbdcec57b-Konachan.com%20-%2027833%20horo%20spice_and_wolf.jpg parent_id= file_size=647053.jpg

Пост был написан для блога welinux.ru
Комментировать Теги: #nix   #bash  

Меню монтирования в OpenBox

23 апреля 2011, 20:43
Буду краток. Давеча, не найдя готового, написал вот такую штуку:



Итак, код:
#!/bin/sh
case "$1" in
openn)
rox $(mount |grep $2 |awk '{print $3}')
;;
moope)
$0 mount $2
$0 openn $2
;;
mount)
LABEL="$(/sbin/blkid -o udev /dev/$2 |grep ID_FS_LABEL\= |awk -F'=' '{print $2}')"
test -z "$LABEL" && LABEL=$2
notify-send -c device.added -i gnome-dev-removable "Монтирование $2" "Точка монтирования: $LABEL"
pmount /dev/$2 "$LABEL"
;;
umoun)
notify-send -i gnome-dev-removable "Отмонтирование $2" "Точка монтирования: $(mount |grep $2 |awk '{print $3}')"
pumount $3 /dev/$2
if [ $? -eq 0 ]; then notify-send -u low -c device.removed -i gnome-dev-removable \
"Устройство $2 отмонтировано" "Теперь это устройство можно безопасно извлечь"
else notify-send -u critical -c device.removed -i gnome-dev-removable "Устройство $2 НЕ отмонтировано" \
"$(lsof $(mount |grep $2 |awk '{print $3}')|awk '{printf $1"("$2") "}')"
fi
;;
umoul)
$0 umoun $2 --lazy
;;
esac
test -n "$*" && exit
echo "<openbox_pipe_menu>"
echo "<separator label=\"Закладки\" />"
for bookmark in `sed 's/< ><^ >*$//' .gtk-bookmarks |sed s/file\://
` ; do
echo '<item label="'`basename ${bookmark}`'">'
echo '<action name="Execute"><execute>'
echo "rox ${bookmark}"
echo '</execute></action>'
echo '</item>'
done
echo "<separator label=\"Устройства\" />"
for i in /sys/block/sd*/; do cd $i; for ii in sd*; do
test -r $ii || continue
test ${ii%?} = sda && continue
VENDOR=$(cat $i/device/vendor |sed 's/ *$//g')
MODEL=$(cat $i/device/model |sed 's/ *$//g')
echo "<menu id=\"$ii\" label=\"$ii <$VENDOR - $MODEL>\">"
echo "<separator label=\"Действия над $ii\"/>"
echo "<item id=\"${ii}_openn\" label=\"Открыть\">"
echo "<action name=\"Execute\"><execute>$0 openn $ii </execute></action>"
echo "</item>"
echo "<item id=\"${ii}_moope\" label=\"Монтировать и открыть\" >"
echo "<action name=\"Execute\"><execute>$0 moope $ii</execute></action>"
echo "</item>"
echo "<item id=\"${ii}_mount\" label=\"Монтировать\" >"
echo "<action name=\"Execute\"><execute>$0 mount $ii</execute></action>"
echo "</item>"
echo "<item id=\"${ii}_umoun\" label=\"Отмонтировать\" >"
echo "<action name=\"Execute\"><execute>$0 umoun $ii</execute></action>"
echo "</item>"
echo "<item id=\"${ii}_umoul\" label=\"Отмонт. принудительно\" >"
echo "<action name=\"Execute\"><execute>$0 umoul $ii</execute></action>"
echo "</item>"
echo "<separator/>"
echo "<item id=\"${ii}_imntpt\" label=\"Точка монт.: $(mount |grep $ii |awk '{print $3}')\" />"
# echo "<item id=\"${ii}_ilabal\" label=\"Метка: $(/sbin/blkid /dev/$ii)\" />"
echo "</menu>"
done; cd -; done
echo "</openbox_pipe_menu>"


Как видно из кода, необходимы pmount, blkid, notify-send, rox (или другой файл-менеджер).

Использование - прописать в menu.xml что-то вроде такого:
<menu id="mounts" label="Монтирование" execute="~/.config/openbox/mountmenu.sh" />

Чтобы заменить файл-менеджер, отредактируйте строки 5 и 37. Чтобы добавить игнорируемые скриптом диски, отредактируйте строку 45.


Пост был написан для блога welinux.ru
Комментировать Теги: #nix   #openbox  

Эмуляция древних консолей

21 июня 2010, 20:59
Многие из нас в 90-е годы имели приставку типа Денди или Сега. Не открою америку, если скажу, что на любом компьютере старше 486sx можно путем программной эмуляции погамать в любимые игрушки. Сейчас я хочу рассмотреть эту тему подробнее. Итак, что нам нужно (для определенности будем дальше работать с консолью NES (ака Денди), но аналагично и для других приставок):

Эмулятор
Это - наш главный инструмент, как скальпель для хирурга и как vim для программиста :) От выбора эмулятора зависит то, насколько комфортно нам будет играть и будет ли вообще игра доставлять удовольствие. Для Linux выбор эмуляторов не так широк как хотелось бы, но для неискушенного пользователя вполне хватит. Мною был выбран Mednafen в первую очередь за универсальность. Он поддерживает кучу различных консолей начиная от всеми известной Денди и заканчивая экзотическим Watara Supervision. Но к сожалению в этом списке пока нет Сеги и Супер Нинтендо :( (может быть кто желает помочь автору с этими консолями?). Главной недостаток и в то же время главное достоинство этого эмулятора - отсутствие какого-либо графического интерфейса в стандартной поставке. С данным вопросом мы разберемся во второй части статьи, а пока опробуем его. Запускаем из консоли, параметром указываем РОМ с игрой, скачанный предварительно с любого из сотен сайтов по этой тематике.
thumb.png
Первый вопрос, который хочется задать: а что тут с управлением? По системным кнопкам информацию можно получить через F1. Из интересных комбинаций тут у нас alt+s для включения возможностей прокрутки назад (о! как этого нехватало на железной Денди, особенно в Battletoads!) и alt+shift+1 для настройки кнопок первого джойстика Денди. Нас попросят по очереди нажать на клавиатуре или джойстике кнопки, соответствующие кнопкам джойстика Денди. Всего на одну кнопку Денди можно назначить до четырех кнопок джоя/клавиатуры. Я назначил стрелки на крестовину, Z и X на A и B, Space на Select и Enter на Start, также задал и соответствующие кнопки железно джойстика Денди, подключенного через переходник на LPT.
С управлением разобрались, теперь второй вопрос на повестке дня - графика. Действительно, умолчальные настройки выглядят весьма непривлекательно. Чтобы подкорректировать их нам придется залезть в конфигурационный файл ~/.mednafen/mednafen.cfg. Пару слов о формате файла: большинство настроек задается отдельно для каждой консоли в виде "консоль.подсистема.параметр значение". Я рассмотрю настройку для Денди(NES), но для других консолей все аналогично. Нас интересует один блок настроек, далее я его приведу с комментариями?

;Разрешение в полноэкранном режиме - ширина
nes.xres 1280
;Разрешение в полноэкранном режиме - высота
nes.yres 800
;Ширина в оконном режиме = 256*это_число
nes.xscale 2.2
;высота в оконном режиме = 240*это_число (или 224 в зависимости от игры)
nes.yscale 2
;Ширина в полноэкранном режиме = 256*это_число
nes.xscalefs 3.4
;высота в полноэкранном режиме = 240*это_число (или 224 в зависимости от игры)
nes.yscalefs 3
;Использовать т.н. scanlines - число - это их процент на экране. Эмулирует вид как на старых телевизорах. вобщем легче посмотреть чем объяснить.
nes.scanlines 8
;Растягивать на весь экран в полноэкранном режиме - тогда параметры nes.xscalefs и nes.yscalefs не используются. ИМХО - на ЖК мониторах лучше смотрится нерастянутое изображение.
nes.stretch 0
;Биллинейная интерполяция - сильно замыливает изображение, рекомендуется только если программные фильтры процессор не вытягивает а scanlines не нравятся
nes.videoip 0
;Программные фильтры. Тут на вкус и цвет. В ассортименте none, scale2x, hq2x, nn2x, nny2x. вместо 2х можно 3х и 4х - тогда изображение будет контрастнее на больших разрешениях и загрузка процессора больше.
nes.special scale2x
;Фильтр OpenGL, чтобы работало нужно параметр "video sdl" заменить на "video gl". варианты: ipxnoty, ipynotx, ipsharper, ipxnotysharper, ipynotxsharper, scale2x (3x/4х/6х/8х)
nes.pixshader none
Все, можно было бы играть, но через консоль запускать неудобно. Нужен комфорт :) И в этом нам поможет...


Каталог
Я бы выделил две категории эмуляторщиков - первые долго бродят по различным онлайн каталогам игр, затем скачивают и запускают понравившуюся игру. С этим все понятно - кликнул на игре, запустился эмулятор и играй. Вторые же как правило скачивают полный набор Good* (реже No-Intro) с целью получить все и сразу. Вот тут здорово помогут каталогизаторы. В свое время я использовал QuickPlay - всем он хорош, но только для Windows. Отсутствие каталога в любимой ОС здорово усложнило задачу - нужно было зайти в папку с архивами, найти нужный, найти файл в нем и наконец запустить игру. Но вскоре чудом (учитывая неразрекламированность проекта) был найден Gelide.
thumb.png
На офсайте можно скачать готовые пакеты под Debian, хотя не так давно мне приходилось компилировать вручную.
Итак, главное его умение - показывать список игр, разделенный по консолям (есть и другие фильтры). Как дополнительные плюшки - он может показывать некоторую полезную информацию о ROM'е и фотки картриджа. Последних у меня не оказалось, поэтому все кроме списка игр, консолей эмуляторов было благополучно убрано. Дальше нам надо добавить наш GoodNES (предварительно найденный и скачанный на просторах сети) в каталог. Тут есть несколько вариантов - в контекстном меню пункта "Nintendo NES" выбираем "Edit" и в открывшемся окне поле "Roms Directory" задаем путь до нашего распакованного ГудНЕСа. Другой вариант - распаковываем прямо в ~/.gelide/Nintendo Nes/roms/. Но так как у меня была необходимость играть и в других ОС, то я выбрал вариант символических ссылок (замечу, что это удобно еще и при перемещении нашей коллекции в другое место - достаточно обновить симлинки и не надо беспокоиться о настройках Gelide).
Итак, GoodNES распакован, теперь нужно в контекстном меню нашей приставки выбрать пункт "Refresh" и вауля - в основной части окна появились наши заветные игры. Однако тут нас ждет большой облом - Mednafen не понимает архивы! Тут можно опустить руки, бросить все и пойти старым путем - запускать игры через файловый менеджер. Но нас-то такими мелочами не остановишь :) По-быстрому был написан скрипт-оболочка для наших эмуляторов:
(Маленькое отступление: в архивах GoodNES с игрой кладется куча разных версий РОМа в т.ч. графических хаков, овердампов , бэддампов и т.д. Естественно, брать первый попавшийся не получится т.к. вполне можем запустить нерабочий РОМ о чем узнаем при зависании где нибудь на последнем уровне :) )

#!/bin/sh

# Name: emu-arc
# Author: Uzix (uzix@jabber.org)
# Description: Script for run ROM's from GoodMerged-archives

sel_rom () {
IFS="" ARC_ALLFILES=`7z l -slt "$ARC_PATH" | grep 'Path = ' | gawk -F ' = ' '{print $2}'`
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '(Beta)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | grep -v '(VS)' | grep -v '\test -z "$ARC_FILE" &&\
ARC_FILE=`echo $ARC_ALLFILES | head -n1`
test -z "$ARC_FILE" &&\
echo E: Could not find any file in archive. &&\
exit 4
}

ARC_PATH=$1
ARC_EMU=$2
ARC_NAME=`echo "${ARC_PATH}" | gawk -F'/' '{print $NF}'`
ARC_TYPE=`echo "${ARC_NAME}" | gawk -F'.' '{print $NF}'`
ARC_FILE='/dev/null'
echo I: Archive patch: ${ARC_PATH}
echo I: Archive name: ${ARC_NAME}
echo I: Archive type: ${ARC_TYPE}

if [ ! -r "${ARC_PATH}" ]; then
echo E: Archive not readable
exit 1
fi

case "${ARC_TYPE}" in
7z|zip|rar)
if [ ! -x "`which 7z`" ]; then
echo E: 7z archiver not found. Please, install it.
exit 2
fi
sel_rom
7z e -y -o"${HOME}" "${ARC_PATH}" "${ARC_FILE}"
;;
*)
echo E: Unrecognized archive type
ARC_FILE="${ARC_NAME}"
ln -fs "`pwd`/${ARC_PATH}" "${HOME}/${ARC_FILE}"
;;
esac

ARC_FTYPE=`echo "${ARC_FILE}" | gawk -F'.' '{print $NF}'`
echo I: Selected file: ${ARC_FILE}
echo I: Selected file type: ${ARC_FTYPE}
if [ ! -x "`which "${ARC_EMU}"`" ]; then
case "${ARC_FTYPE}" in
nes|fds|sms|gg|gb|gbc|gba|ws|wsc|pce|ngp|ngc)
for i in mednafen; do
test -x "`which $i`" && ARC_EMU="$i"
done
;;
bin|smd)
for i in dgen gens; do
test -x "`which $i`" && ARC_EMU="$i"
done
;;
smc)
for i in bsnes snes9x zsnes; do
test -x "`which $i`" && ARC_EMU="$i"
done
;;
esac
fi
if [ -z "${ARC_EMU}" ]; then
echo E: Could not find suitable emulator
exit 3
fi
echo I: Selected emulator: ${ARC_EMU}
xdg-screensaver suspend `xwininfo -root |grep id\: | awk '{print $4}'`
"${ARC_EMU}" "${HOME}/${ARC_FILE}"
xdg-screensaver resume `xwininfo -root |grep id\: | awk '{print $4}'`
rm "${HOME}/${ARC_FILE}"
exit 0



Что он делает? Он смотрит содержимое архива с помощью 7z, выбирает наилучший РОМ (функция sel_rom), распаковывает его, ищет подходящий эмулятор и запускает все это. Помещаем скрипт в /usr/local/bin/ и даем ему +x. Теперь нужно добавить скрипт в Gelide в качестве эмулятора. Для этого вызываем контекстное меню во фрейме с эмуляторами и жмем "Add". Заполняем примерно так:
thumb.png
Готово! Теперь можно и поиграть! выбираем любимую игру, выбираем скрипт emu-arc и... В БОЙ! :-)



P.S. Не злоупотребляйте сохранениями :)

P.P.S. Если будет необходимость, добавлю описание настройки dgen (эмулятор сеги) и zsnes (супер нинтендо)

P.P.P.S. Первый пост.

Пост был написан для блога welinux.ru
Комментировать Теги: #nix   #денди   #игры   #эмуляция  

Секунда координации

1 июля 2015, 08:45
Быстрофикс зависших серверов:
/etc/init.d/ntp stop; date; date `date +"%m%d%H%M%C%y.%S"`; date; /etc/init.d/ntp start
Комментировать Теги: #nix   #время  
1  2