Показаны сообщения с ярлыком ubuntu. Показать все сообщения
Показаны сообщения с ярлыком ubuntu. Показать все сообщения

среда, 11 января 2017 г.

Гайд по обеспечению безопасности Linux-системы


Коллега на работе показал мне статью из журнала Хакер по защите систем на базе Linux.
Статья просто великолепна, и, учитывая, что интернет сейчас активно перлюстрируется размещаю ее у себя в блоге. На всякий случай




Введение
Пароль
Шифруемся
Заметаем следы
Предотвращение BruteForce-атак
Угроза извне
Выявляем вторжения
Кто-то наследил…
За пределами
Луковая маршрутизация
Борьба с флудом
Выводы


Никто из нас не хочет, чтобы личная информация попала в чужие руки. Но как защитить систему от атак и хищений данных? Неужели придется читать километровые мануалы по настройке и алгоритмам шифрования? Совсем не обязательно. В этой статье я расскажу, как сделать Linux-систему безопасной буквально за 30 минут.


Введение

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

Когда я потерял смартфон, мне сильно повезло, что установленный на него антивор оказался работоспособным и позволил удаленно стереть все данные из памяти девайса. Когда я по невнимательности открыл SSH-порт на домашней машине с юзером без пароля (!) во внешний мир (!!), мне сильно повезло, что на машину пробрались скрипт-кидди, которые кроме смешной истории шелла не оставили никаких серьезных следов своего пребывания в системе. Когда я случайно опубликовал в интернете листинг со своим паролем от Gmail, мне сильно повезло, что нашелся добрый человек, который предупредил меня об этом.

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

Эта статья — гайд параноидального юниксоида, посвященный тотальной защите Linux-машины от всего и вся. Я не решусь сказать, что все описанное здесь обязательно к применению. Совсем наоборот, это сборник рецептов, информацию из которого можно использовать для защиты себя и данных на тех рубежах, где это нужно именно в твоей конкретной ситуации.


Пароль!

Все начинается с паролей. Они везде: в окне логина в Linux-дистрибутиве, в формах регистрации на интернет-сайтах, на FTP- и SSH-серверах и на экране блокировки смартфона. Стандарт для паролей сегодня — это 8–12 символов в разном регистре с включением цифр. Генерировать такие пароли своим собственным умом довольно утомительно, но есть простой способ сделать это автоматически:

$ openssl rand -base64 6

Никаких внешних приложений, никаких расширений для веб-браузеров, OpenSSL есть на любой машине. Хотя, если кому-то будет удобней, он может установить и использовать для этих целей pwgen (поговаривают, пароль получится более стойким):

$ pwgen -Bs 8 1

Где хранить пароли? Сегодня у каждого юзера их так много, что хранить все в голове просто невозможно. Довериться системе автосохранения браузера? Можно, но кто знает, как Google или Mozilla будет к ним относиться. Сноуден рассказывал, что не очень хорошо. Поэтому пароли надо хранить на самой машине в зашифрованном контейнере. Отцы-основатели рекомендуют использовать для этого KeePassX. Штука графическая, что не сильно нравится самим отцам-основателям, но зато работает везде, включая известный гугль-зонд Android (KeePassDroid). Останется лишь перекинуть базу с паролями куда надо.


Шифруемся

Шифрование — как много в этом слове… Сегодня шифрование везде и нигде одновременно. Нас заставляют пользоваться HTTPS-версиями сайтов, а нам все равно. Нам говорят: «Шифруй домашний каталог», а мы говорим: «Потом настрою». Нам говорят: «Любимое занятие сотрудников Dropbox — это ржать над личными фотками юзеров», а мы: «Пусть ржут». Между тем шифрование — это единственное абсолютное средство защиты на сегодняшний день. А еще оно очень доступно и сглаживает морщины.

В Linux можно найти тонны средств шифрования всего и вся, от разделов на жестком диске до одиночных файлов. Три наиболее известных и проверенных временем инструмента — это dm-crypt/LUKS, ecryptfs и encfs. Первый шифрует целые диски и разделы, второй и третий — каталоги с важной информацией, каждый файл в отдельности, что очень удобно, если потребуется делать инкрементальные бэкапы или использовать в связке с Dropbox. Также есть несколько менее известных инструментов, включая TrueCrypt например.

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

$ sudo apt-get install ecryptfs-utils

И, собственно, включить шифрование:

$ sudo ecryptfs-setup-swap
$ ecryptfs-setup-private

Далее достаточно ввести свой пароль, используемый для логина, и перезайти в систему. Да, все действительно так просто. Первая команда зашифрует и перемонтирует своп, изменив нужные строки в /etc/fstab. Вторая — создаст каталоги ~/.Private и ~/Private, в которых будут храниться зашифрованные и расшифрованные файлы соответственно. При входе в систему будет срабатывать PAM-модуль pam_ecryptfs.so, который смонтирует первый каталог на второй с прозрачным шифрованием данных. После размонтирования ~/Private окажется пуст, а ~/.Private будет содержать все файлы в зашифрованном виде.

Не возбраняется шифровать и весь домашний каталог целиком. Производительность при этом упадет не сильно, зато под защитой окажутся вообще все файлы, включая тот же сетевой каталог ~/Dropbox. Делается это так:

# ecryptfs-migrate-home -u vasya

Кстати, места на диске должно быть в 2,5 раза больше, чем данных у vasya, так что рекомендую заранее почиститься. После завершения операции следует сразу войти под юзером vasya и проверить работоспособность:

$ mount | grep Private
/home/vasya/.Private on /home/vasya type ecryptfs ...

Если все ок, незашифрованную копию данных можно затереть:

$ sudo rm -r /home/vasya.*

Ecryptfs предупреждает нас


Заметаем следы

ОK, пароли в надежном месте, личные файлы тоже, что теперь? А теперь мы должны позаботиться о том, чтобы какие-то куски наших личных данных не попали в чужие руки. Ни для кого не секрет, что при удалении файла его актуальное содержимое остается на носителе даже в том случае, если после этого произвести форматирование. Наши зашифрованные данные будут в сохранности даже после стирания, но как быть с флешками и прочими картами памяти? Здесь нам пригодится утилита srm, которая не просто удаляет файл, но и заполняет оставшиеся после него блоки данных мусором:

$ sudo apt-get install secure-delete
$ srm секретный-файл.txt home-video.mpg

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

# dd if=/dev/zero of=/dev/sdb

Эта команда сотрет все данные на флешке sdb. Далее останется создать таблицу разделов (с одним разделом) и отформатировать в нужную ФС. Использовать для этого рекомендуется fdisk и mkfs.vfat, но можно обойтись и графическим gparted.


Предотвращение BruteForce-атак

Fail2ban — демон, который просматривает логи на предмет попыток подобрать пароли к сетевым сервисам. Если такие попытки найдены, то подозрительный IP-адрес блокируется средствами iptables или TCP Wrappers. Сервис способен оповещать владельца хоста об инциденте по email и сбрасывать блокировку через заданное время. Изначально Fail2ban разрабатывался для защиты SSH, сегодня предлагаются готовые примеры для Apache, lighttpd, Postfix, exim, Cyrus IMAP, named и так далее. Причем один процесс Fail2ban может защищать сразу несколько сервисов.

В Ubuntu/Debian для установки набираем:

# apt-get install fail2ban

Конфиги находятся в каталоге /etc/fail2ban. После изменения конфигурации следует перезапускать fail2ban командой:

# /etc/init.d/fail2ban restart

Угроза извне

Теперь позаботимся об угрозах, исходящих из недр всемирной паутины. Здесь я должен был бы начать рассказ об iptables и pf, запущенном на выделенной машине под управлением OpenBSD, но все это излишне, когда есть ipkungfu. Что это такое? Это скрипт, который произведет за нас всю грязную работу по конфигурированию брандмауэра, без необходимости составлять километровые списки правил. Устанавливаем:

$ sudo apt-get install ipkungfu

Правим конфиг:

$ sudo vi /etc/ipkungfu/ipkungfu.conf
# Локальная сеть, если есть — пишем адрес сети вместе с маской, нет — пишем loopback-адрес
LOCAL_NET="127.0.0.1"

# Наша машина не является шлюзом
GATEWAY=0

# Закрываем нужные порты
FORBIDDEN_PORTS="135 137 139"

# Блокируем пинги, 90% киддисов отвалится на этом этапе
BLOCK_PINGS=1

# Дропаем подозрительные пакеты (разного рода флуд)
SUSPECT="DROP"

# Дропаем «неправильные» пакеты (некоторые типы DoS)
KNOWN_BAD="DROP"

# Сканирование портов? В трэш!
PORT_SCAN="DROP"

Для включения ipkungfu открываем файл /etc/default/ipkungfu и меняем строку IPKFSTART = 0 на IPKFSTART = 1. Запускаем:

$ sudo ipkungfu

Дополнительно внесем правки в /etc/sysctl.conf:

$ sudo vi /etc/systcl.conf
# Дропаем ICMP-редиректы (против атак типа MITM)
net.ipv4.conf.all.accept_redirects=0
net.ipv6.conf.all.accept_redirects=0
# Включаем механизм TCP syncookies
net.ipv4.tcp_syncookies=1
# Различные твики (защита от спуфинга, увеличение очереди «полуоткрытых» TCP-соединений и так далее)
net.ipv4.tcp_timestamps=0
net.ipv4.conf.all.rp_filter=1
net.ipv4.tcp_max_syn_backlog=1280
kernel.core_uses_pid=1

Активируем изменения:

$ sudo sysctl -p

Выявляем вторжения

Snort — один из любимейших инструментов админов и главный фигурант всех руководств по безопасности. Штука с долгой историей и колоссальными возможностями, которой посвящены целые книги. Что он делает в нашем гайде по быстрой настройке безопасной системы? А здесь ему самое место, Snort можно и не конфигурировать:

$ sudo apt-get install snort
$ snort -D

Все! Я не шучу, стандартных настроек Snort более чем достаточно для защиты типовых сетевых сервисов, если, конечно, они у тебя есть. Нужно только время от времени просматривать лог. А в нем можно обнаружить строки типа этих:

[**] [1:2329:6] MS-SQL probe response overflow attempt [**]
[Classification: Attempted User Privilege Gain] [Priority: 1]
[Xref => [url]http://www.securityfocus.com/bid/9407][/url]

Упс. Кто-то пытался вызвать переполнение буфера в MySQL. Тут сразу есть и ссылочка на страницу с детальным описанием проблемы. Красота.


Кто-то наследил…

Кто-то особенно умный смог обойти наш брандмауэр, пройти мимо Snort, получить права root в системе и теперь ходит в систему регулярно, используя установленный бэкдор. Нехорошо, бэкдор надо найти, удалить, а систему обновить. Для поиска руткитов и бэкдоров используем rkhunter:

$ sudo apt-get install rkhunter

Запускаем:

$ sudo rkhunter -c --sk

Софтина проверит всю систему на наличие руткитов и выведет на экран результаты. Если зловред все-таки найдется, rkhunter укажет на место и его можно будет затереть. Более детальный лог располагается здесь: /var/log/rkhunter.log. Запускать rkhunter лучше в качестве cron-задания ежедневно:

$ sudo vi /etc/cron.daily/rkhunter.sh
#!/bin/bash
/usr/bin/rkhunter -c --cronjob 2>&1 | mail -s "RKhunter Scan Results" vasya@email.com

Заменяем email-адрес Васи на свой и делаем скрипт исполняемым:

$ sudo chmod +x /etc/cron.daily/rkhunter.sh

Базу rkhunter рекомендуется время от времени обновлять с помощью такой команды:

$ sudo rkhunter --update

Ее, кстати, можно добавить перед командой проверки в cron-сценарий. Еще два инструмента поиска руткитов:

$ sudo apt-get install tiger
$ sudo tiger
$ sudo apt-get install lynis
$ sudo lynis -c

По сути, те же яйца Фаберже с высоты птичьего полета, но базы у них различные. Возможно, с их помощью удастся выявить то, что пропустил rkhunter. Ну и на закуску debsums — инструмент для сверки контрольных сумм файлов, установленных пакетов с эталоном. Ставим:

$ sudo apt-get install debsums

Запускаем проверку:

$ sudo debsums -ac

Как всегда? запуск можно добавить в задания cron.

rkhunter за работой

В моей системе руткитов нет


За пределами

Теперь поговорим о том, как сохранить свою анонимность в Сети и получить доступ к сайтам и страницам, заблокированным по требованию различных организаций-правообладателей и прочих Мизулиных. Самый простой способ сделать это — воспользоваться одним из тысяч прокси-серверов по всему миру. Многие из них бесплатны, но зачастую обрезают канал до скорости древнего аналогового модема.

Чтобы спокойно ходить по сайтам и только в случае необходимости включать прокси, можно воспользоваться одним из множества расширений для Chrome и Firefox, которые легко находятся в каталоге по запросу proxy switcher. Устанавливаем, вбиваем список нужных прокси и переключаемся на нужный, увидев вместо страницы табличку «Доступ к странице ограничен по требованию господина Скумбриевича».

В тех ситуациях, когда под фильтр попал весь сайт и его адрес внесли в черный список на стороне DNS-серверов провайдеров, можно воспользоваться свободными DNS-серверами, адреса которых опубликованы здесь. Просто берем два любых понравившихся адреса и добавляем в /etc/resolv.conf:

nameserver 156.154.70.22
nameserver 156.154.71.22

Чтобы разного рода DHCP-клиенты и NetworkManager’ы не перезаписали файл адресами, полученными от провайдера или роутера, делаем файл неперезаписываемым с помощью расширенных атрибутов:

$ sudo chattr +i /etc/resolv.conf

После этого файл станет защищен от записи для всех, включая root.

Чтобы еще более анонимизировать свое пребывание в Сети, можно воспользоваться также демоном dnscrypt, который будет шифровать все запросы к DNS-серверу в дополнение к прокси-серверу, используемому для соединения с самим сайтом. Устанавливаем:

$ wget http://download.dnscrypt.org/dnscrypt-proxy/dnscrypt-proxy-1.3.2.tar.bz2
$ bunzip2 -cd dnscrypt-proxy-*.tar.bz2 | tar xvf -
$ cd dnscrypt-proxy-*
$ sudo apt-get install build-essential
$ ./configure && make -j2
$ sudo make install

Указываем в /etc/resolv.conf loopback-адрес:

$ vi /etc/resolv.conf
nameserver 127.0.0.1

Запускаем демон:

$ sudo dnscrypt-proxy --daemonize

Кстати, версии dnscrypt есть для Windows, iOS и Android.


Луковая маршрутизация

Что такое луковая маршрутизация? Это Tor. А Tor, в свою очередь, — это система, которая позволяет создать полностью анонимную сеть с выходом в интернет. Термин «луковый» здесь применен относительно модели работы, при которой любой сетевой пакет будет «обернут» в три слоя шифрования и пройдет на пути к адресату через три ноды, каждая из которых будет снимать свой слой и передавать результат дальше. Все, конечно, сложнее, но для нас важно только то, что это один из немногих типов организации сети, который позволяет сохранить полную анонимность.

Тем не менее, где есть анонимность, там есть и проблемы соединения. И у Tor их как минимум три: он чудовищно медленный (спасибо шифрованию и передаче через цепочку нод), он будет создавать нагрузку на твою сеть (потому что ты сам будешь одной из нод), и он уязвим для перехвата трафика. Последнее — естественное следствие возможности выхода в интернет из Tor-сети: последняя нода (выходная) будет снимать последний слой шифрования и может получить доступ к данным.

Тем не менее Tor очень легко установить и использовать:

$ sudo apt-get install tor

Все, теперь на локальной машине будет прокси-сервер, ведущий в сеть Tor. Адрес: 127.0.0.1:9050, вбить в браузер можно с помощью все того же расширения, ну или добавить через настройки. Имей в виду, что это SOCKS, а не HTTP-прокси.


Борьба с флудом

Приведу несколько команд, которые могут помочь при флуде твоего хоста.

Подсчет количества коннектов на определенный порт:

$ netstat -na | grep ":порт\ " | wc -l

Подсчет числа «полуоткрытых» TCP-соединений:

$ netstat -na | grep ":порт\ " | grep SYN_RCVD | wc -l

Просмотр списка IP-адресов, с которых идут запросы на подключение:

$ netstat -na | grep ":порт\ " | sort | uniq -c | sort -nr | less

Анализ подозрительных пакетов с помощью tcpdump:

# tcpdump -n -i eth0 -s 0 -w output.txt dst port порт and host IP-сервера

Дропаем подключения атакующего:

# iptables -A INPUT -s IP-атакующего -p tcp --destination-port порт -j DROP

Ограничиваем максимальное число «полуоткрытых» соединений с одного IP к конкретному порту:

# iptables -I INPUT -p tcp --syn --dport порт -m iplimit --iplimit-above 10 -j DROP

Отключаем ответы на запросы ICMP ECHO:

# iptables -A INPUT -p icmp -j DROP --icmp-type 8

Выводы

Вот и все. Не вдаваясь в детали и без необходимости изучения мануалов мы создали Linux-box, который защищен от вторжения извне, от руткитов и прочей заразы, от непосредственно вмешательства человека, от перехвата трафика и слежки. Остается лишь регулярно обновлять систему, запретить парольный вход по SSH, убрать лишние сервисы и не допускать ошибок конфигурирования.

вторник, 6 сентября 2016 г.

Раскладывание книжек по полкам в Kobo



Version 0.9 build 2016-09-06

Наверное самая глупая фишка в ридерах от Kobo - это так называемые книжные полки. Единственное преимущество перед хранением книг в директориях - возможность поместить книгу сразу в две и более полок. Довольно сомнительная возможность.

Я не использую Caliber и просто закидываю книги в ридер. Иногда раскладывал по полкам. Но после того, как полки несколько раз слетели, перестал это делать. Как то мне ночью не спалось и я написал скрип на python, который раскладывает книги по полкам.


Как это работает.

В основной памяти и на карточке я создал корневую директорию /Books. Внутри - отдельные директории для серий, в которые я копирую книги.


Потом запускаю скрипт.
Скрипт сначала очищает две таблицы: Shelf и ShelfContent. Потом сканирует папку Books и записывает названия вложенных папок в Shelf и собственно книги в ShelfContent.

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


Установка Python

Для работы скрипта необходимо, что бы на вашем компьютере был установлен Pyton 3.

Если у Вас Ubuntu, nо Python 3.5 уже скорее всего установлен. В противном случае выполните команду:

sudo add-apt-repository ppa:fkrull/deadsnakes
sudo apt-get update
sudo apt-get install python3.5

Если у Вас Windows, то установите Python 3.5.2 - 2016-06-27 отсюда:
https://www.python.org/downloads/windows/


Как использовать.
  1. Сохраните скрипт в файл KoboShelf.py и дайте ему права на исполнение:
    chmod +x KoboShelf.py
    
  2. В каталоге .kobo в разделе KOBOeReader сделайте резервную копию базы данных.
    cp KoboReader.sqlite KoboReader.sqlite.origin
    
  3. Создайте папку /Books на карточке, в ней папки с сериями, в них скопируйте ваши книги.
  4. Запустите из терминала вышеуказанный скрипт. В терминале будут показаны найденные полки и книги, которые в них добавлены.
    Скрипт отрабатывает очень быстро, около секунды.
  5. Безопасно извлеките ридер.

Командная Строка

В Linux и в Windows скрипт автоматически определяет точки монтирования Kobo и SD карты. Поэтому для создания полок никакие аргументы в команде запуска не нужны.

./KoboShelf.py -h
usage: KoboShelf.py [-h] [--onboard ONBOARD] [--sd SD] [--onboard_sw {on,off}]
                    [--sd_sw {on,off}] [-s] [-v]

optional arguments:
  -h, --help            show this help message and exit
  --onboard ONBOARD     eReaders mount point
  --sd SD               SD cards mount point
  --onboard_sw {on,off}
                        Enabling/disabling adding book from eReader onboard
                        memory. Enabled by default
  --sd_sw {on,off}      Enabling/disabling adding book from SD card memory.
                        Enabled if SD card present
  -s, --showsettings    Display settings and exit. Reader must be connected.
  -v, --version         show program's version number and exit


Какие могут быть траблы.

Скрипт в стадии экспериментальной, поэтому возможно все. Если по какой то причине испортилась база данных KoboReader.sqlite, то восстанавливаем ее из сохраненной копии.
Как всегда, все вы выполняете на свой страх и риск. Я ни за что не отвечаю.

Исходный код можно посмотреть в Git репозитории:

https://github.com/Axa-Ru/KoboShelfes/blob/master/KoboShelf.py

В скрипте меняйте, что хотите, хоть автора, хоть код. :P

Всем удачи.

среда, 17 августа 2016 г.

VMWare 12.1.1. на ядре 4.6.4 и 4.7


Для запуска VMWare на Ubuntu 16.04 на ядрах выше 4.2 необходимо пропатчить ядро.
Для 4.6.4 нашел в сети вот этот патч


#!/bin/bash
usr=`whoami`
if [ "$usr" != "root" ]; then
    echo "Run $0 ar superuser"
    exit 1
fi

WORKDIR=/tmp/vmw
SRCDIR=/usr/lib/vmware/modules/source
MODDIR=/lib/modules/`uname -r`/kernel/misc
mkdir $WORKDIR
mkdir $MODDIR
cp $SRCDIR/vmmon.tar $WORKDIR/
cp $SRCDIR/vmnet.tar $WORKDIR/
cd $WORKDIR
tar -xf vmmon.tar
tar -xf vmnet.tar
cd vmnet-only
# cat netif.c | sed -r 's/dev->trans_start = jiffies/netif_trans_update(dev)/g' > netif.c1
# mv netif.c1 netif.c
cat userif.c | sed -r 's/get_user_pages/get_user_pages_remote/g' > userif.c1
mv userif.c1 userif.c
make
cp *.ko $MODDIR/
cd ../vmmon-only/linux
cat hostif.c | sed -r 's/get_user_pages/get_user_pages_remote/g' > hostif.c1
mv hostif.c1 hostif.c
cd ../
make
cp *.ko $MODDIR/
depmod -a
modprobe vmnet
modprobe vmmon
rm -R $WORKDIR
Скрипт сохранить в любой каталог, дать права на исполнение и запустить под root.
Для ядер 4.6.7 этот патч не работает.

Для ядра 4.7 запускаем этот патч:
#!/bin/bash
usr=`whoami`
if [ "$usr" != "root" ]; then
  echo "Run $0 ar superuser"
  exit 1
fi
WORKDIR=/tmp/vmw
SRCDIR=/usr/lib/vmware/modules/source
MODDIR=/lib/modules/`uname -r`/kernel/misc
mkdir $WORKDIR
mkdir $MODDIR
cp $SRCDIR/vmmon.tar $WORKDIR/
cp $SRCDIR/vmnet.tar $WORKDIR/
cd $WORKDIR
tar -xf vmmon.tar
tar -xf vmnet.tar
cd vmnet-only
cat netif.c | sed -r 's/dev->trans_start = jiffies/netif_trans_update(dev)/g' > netif.c1
mv netif.c1 netif.c
cat userif.c | sed -r 's/get_user_pages/get_user_pages_remote/g' > userif.c1
mv userif.c1 userif.c
make
cp *.ko $MODDIR/
cd ../vmmon-only/linux
cat hostif.c | sed -r 's/get_user_pages/get_user_pages_remote/g' > hostif.c1
mv hostif.c1 hostif.c
cd ../
make
cp *.ko $MODDIR/
depmod -a
modprobe vmnet
modprobe vmmon
rm -R $WORKDIR
Ветка обсуждения на rutracker.

вторник, 1 марта 2016 г.

Устанавливаем PyQt в Ubuntu

Если вы не знаете, что такое PyQt то отправлю Вас в википедию. Там все коротко и по существу.
Если Вы не знаете, что такое Python, то может и к лучшему. Ну, или опять в википедию.

Вернулись?
Ну тогда вперед!

Сначала подготовим место, где будем проводить работу с пакетами. Я обычно делаю это в директории ~/tmp

Устанавливаем пакеты, необходимые для установки и работы PyQt

sudo apt-get install build-essential python3-dev python3-pyqt5 pyqt5-dev-tools

Скачиваем и устанавливаем SIP

wget http://sourceforge.net/projects/pyqt/files/sip/sip-4.17/sip-4.17.tar.gz
tar -xzf sip-4.17.tar.gz
cd sip-4.17
sudo python3 configure.py
make
sudo make install

Скачиваем и устанавливаем PyQT5

wget http://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.5.1/PyQt-gpl-5.5.1.tar.gz
tar -xzf PyQt-gpl-5.5.1.tar.gz
cd PyQt-gpl-5.5.1
sudo python3 configure.py
sudo make
sudo make install

Вот и все. Установка завершена.
Теперь для проверки создадим небольшую программу на Python. Назовем ее pyqt_test.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-
 
import sys
from PyQt5.QtWidgets import QApplication, QWidget
 
 
if __name__ == '__main__':
 
    app = QApplication(sys.argv)
 
    w = QWidget()
    w.resize(250, 150)
    w.move(300, 300)
    w.setWindowTitle('PyQT установлен')
    w.show()
 
    sys.exit(app.exec_())



Дадим файлу pyqt_test.py права на исполнение и запустим:

chmod +x pyqt_test.py
./pyqt_test.py

Если мы увидим такой результат, то это значит, что мы все сделали правильно и установили PyQt.



Полезные ссылки:

четверг, 17 декабря 2015 г.

Система видеонаблюдения для входной двери. 2. Купольная камера на лестничной площадке.

Для получения качественной картинки было решено установить купольную камеру на лестничной площадке. Для этой цели очень давно, больше года назад, я купил камеру ITP-020RT45N. Кто ее производит мне неизвестно. Производит ее мне неизвестная компания с название IIT. Продают эти камеры в основном в Беларусии.

Сенсор: 1/2.8" SONY 2.4 CMOS
Firmware ver.: DM368+IMX222_3.0.9.0
Software ver.: 4.1.0.20
Разрешение: 1080P (1920×1080), 720P (1280x720)
Линза: 2.8 - 12 мм
Чувствительность: 0,01 Люкс
Отношение сигнал/шум: >50дБ
Рабочее расстояние ИК подсветки: 20M
Интерфейс: RJ45 Ethernet
Питание: DC 12V/1000MA
Диапазон температур: -20 ~ 50°C
Защищенность: IP65
Размеры: 149 x 99(В)мм

Интерфейс управления камерой привязан к Windows IE c active X.
Разрешение камеры действительно высокое. Но шум тоже великоват (возможно это мои придирки). Скриншот с камеры при нормальном уровне освещенности. Тестовый лист находится на расстоянии около 3,5 метров от камеры.


Видео при хорошей освещенности. К сожалению, пришлось уменьшить размер и соответственно уменьшилось разрешение.
Если с RVi-R04La White я снимал поток rtsp с помощью totem, то с камерой он работать отказался и для трансляции я использовал vlc:

vlc "rtsp://user:password@192.168.1.14/0"

среда, 16 декабря 2015 г.

Система видеонаблюдения для входной двери. 1. Глазок.

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

Собственно видеокамера продающаяся на Ali меня толкнула на такую поделку. Прикупил я безымянный глазок CMOS PC1089 800TVL PEEPHOLE DOORVIEW и систему записи RVi-H04La.

Сначала про камеру.

Внешне выглядит довольно качественно. Черненный алюминиевый корпус. Система линз, дающая широкий угол обзора, как у обычного дверного глазка.
Камера является аналоговой и имеет два разъёма подключения: питание 12 В и выход видео.
Продавец утверждал, что камера имеет разрешение 800 TVL.
Регистратор выдает поток 960x576

Stream #0.0: Video: libx264, yuv420p, 960x576, q=-1--1, 25 tbn, 25 tbc

Для тестирования я разместил перед камерой на расстоянии одного метра тестовую таблицу, напечатанную на листе А4, аналогичную той, что используется для проверки зрения.

Видео записывал, подключившись к регистратору RVi-H04La следующей командой:

avconv -f rtsp -i "rtsp://user:password@192.168.1.12:554/cam/realmonitor?channel=1&subtype=0" -y "PC1089_800TVL_low_light.mp4"

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



При свете показывает лучше.



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

воскресенье, 13 декабря 2015 г.

Настройка Ubuntu и dd-wrt для подключения к домашней сети по vpn.

Зачастую бывает полезно подключиться к домашней локальной сети с работы. Например, чтобы скачать какой нибудь файл. Или сохранить какой нибудь файл. Или дать команду торрент серверу загрузить кино, чтобы вечером его посмотреть.
Для этой цели очень удобно настроить на роутере vpn сервер. Делается это не просто, а очень просто.
Оригинальное полное описание полей находится в wiki  

Настройка сервера
Думаю, картинки достаточно для понимания.

Нужно просто:
  1. включить pptp сервер 
  2. указать диапазон адресов из пула внутренней сети (192.168.1.180-182). В моем случае я разрешаю 3 одновременных коннекта. 
  3. придумать логин и пароль для входа и записать их в поле CHAP-Secrets 
  4. запомнить внешний ip адрес (в скриншоте для примера я нарисовал WAN IP: 1.2.3.4, у вас, естественно, будет другой) 

Я отключил шифрование указав в поле MPPE Encryption Disable, потому как с шифрованием у меня подключение на заработало. (В интернетах пишут, что на некоторых прошивках dd-wrt так бывает.
Так же пишут, что это несовместимость реализации шифрования на стороне клиента Ubuntu [1] [2] [3]).
Поля DNS1, DNS2, WINS1, WINS2 в нашем случае не нужны.
В поле Server IP нужно указать адрес, который будет назначен виртуальному серверу. Я указал свободный в моей сети 192.168.1.2. Можно указать 0.0.0.0

Настройка клиента
На клиентской машине (Ubuntu 14.04) создаем vpn подключение (на скриншотах у меня уже присутствует настроенное соединение с именем Home VPN connection):

1.
2.
3.
4.


Указываем наш WAN IP: 1.2.3.4 (вместо 1.2.3.4 поставьте ваш реальный адрес) и логин-пароль
5.


На этом настройка закончена.

Если что то пошло не так и не создается соединение, то можно посмотреть процесс установления соединения в реальном времени.
Для этого открываем окно терминала и даем команду:
sudo tail -f /var/log/syslog
Небольшое но важное дополнение.
Если номера сеток где вы сейчас находитесь и домашней совпадают, то туннель работать не будет. Поэтому, чтобы снизить вероятность такого события выберите номер домашней сетки, который не используется в примерах и учебниках. Например 192.168.142.0.

Скоростные показатели.
Поскольку роутер имеет не очень мощный процессор скорость через туннель не превышает в моем случае 15 Mbps. Процессор при этом загружен полностью.


Напочитать для знаний:
PPTP Client. Routing HOWTO

суббота, 7 декабря 2013 г.

Аудио книги

В последнее время пристрастился я слушать аудио книги. Слушаю на сматрфоне LG Optimus G e975

Слушаю с помощью программы Ambling BookPlayer. Автор этой программы залег на дно, и уже не принимает советов и просьб по усовершенствованию программы (а у меня есть пара идеек). Зато GooglePlay уверенно принимает деньги за эту программу, чем я и воспользовался.

Аудио книги почему то принято разбивать на огромное количество файлов. Даже если один файл - одна глава, все равно это как то надумано. Мне почему то не нравится такая файло-помоечная структура. По крайней мере хранить этот бардак неудобно.

Я написал на bash небольшую программку, которая объединяет эти файлы в один, а заодно создает XML файл для экспорта в bookreader.
Работает она из под наутилуса Ubuntu.
#!/bin/bash
#----------------------------------------------------------------------
# Программа объеденения музыкальных файлов (книг)
# Для установки скопировать в папку 
#  ~/.local/share/nautilus/scripts

#----------------------------------------------------------------------
# --- Версионность ---
# Начальная версия
#VERSION=0.1
# улучшение алгоритмов кодирования
#VERSION=0.2
#VERSION=0.3
# Заполнение полей в соответствии с xml описанием для импорта в ambling book reader
#VERSION=0.4
# Добавлено переименование обложки в соответствии с названием книги.
#VERSION=0.41
# Баг. Обложка не конвертится. (fixed)
# Добавить полоску времени, а не пульсар (fixed)
#VERSION=0.42
# Добавлено управление битрейтом, генерацией Обложки, XML, результирующего файла (fixed)
VERSION=0.43

#----------------------------------------------------------------------
# Переменные и константы
ERROR=192
INPUT="concat:"
BITRATE="96k|32k|64k|128k|192k|256k"
MIN_BITRATE="96k|32k|64k|128k|192k|256k"
MAX_BITRATE="96k|32k|64k|128k|192k|256k"
CODEC="libvorbis"
CURENT_DIR=$(pwd)
IN_DURATION=0
CREATE_COVER=TRUE
CREATE_XML=TRUE
CREATE_ONEOGG=TRUE

#----------------------------------------------------------------------
# xml ambling bookplayer Tags
BOOK_NAME=""
AUTHOR_NAME=""
NARRATOR_NAME=""
PUBLISHER=""
COPYRIGHT=""
IMAGE_FILE_NAME=""
SERIES_NAME=""
SERIES_SEQUENCE=""

#----------------------------------------------------------------------
# audiofile Tags (атавизм, времени не было сделать ревизию)
TITLE=""
ARTIST=""
ALBUM_ARTIST=""
ALBUM=""
GENRE="AudioBook"
DATE=""
TRACK=""
PUBLISHER=""
ENCODED_BY=""
COPYRIGHT=""
COMPOSER=""
PERFORMER=""
DISC=""
ENCODER="ffmpeg"
COVER=""

check_installed()
{
  PKG_OK=$(dpkg-query -W --showformat='${Status}\n' $1 |grep "install ok installed")

  if [ "" == "$PKG_OK" ]; then
    zenity --no-wrap --error --text="$1 package not found!\n Install it"
    exit $ERROR
  fi
}

# Выход по ошибке
exit_on_error()
{
  yad --title "Error" --text "$1" 200 200
  exit 192
}

# Возвращает в секундах время звучания звукового файла
duration()
{
  RET=$(ffmpeg -i "$1" 2>&1 | grep Duration | awk '{ print $2 }' | tr -d ',')
  S=$(echo ${RET:0:2}*60*60+${RET:3:2}*60+${RET:6:2} | bc)
  echo $S
}

check_nautilus_env()
{
  #--------------------------------------------------------------------
  # Сохраняем для отладки
  echo "Аргументы командной строки запуска скрипта в Nautius" >> tst.txt
  echo "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" >> tst.txt
  echo "" >> tst.txt

  if [ "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" == "" ]; then
    echo "Этот скрипт запускается из под наутилуса"
    exit_on_error
  fi
}

#######################################################################
#                                Main code
#

#----------------------------------------------------------------------
check_nautilus_env
check_installed yad
check_installed python-mutagen

#----------------------------------------------------------------------
# Получаем имена тегов

AUTHOR_NAME=$(mid3iconv --encoding=Windows-1251 --dry-run --debug "$1" | grep TPE1 | sed 's/TPE1=//')
if [ "$AUTHOR_NAME" == "" ]; then
  AUTHOR_NAME="$1"
fi

BOOK_NAME=$(mid3iconv --encoding=Windows-1251 --dry-run --debug "$1" | grep TIT2 | sed 's/TIT2=//')
if [ "$BOOK_NAME" == "" ]; then
  BOOK_NAME="$1"
fi

SERIES_NAME="$BOOK_NAME"

TAGS=$(yad --geometry=400x200 --center\
    --title="Enter Track Tags" \
    --form --text="$CURENT_DIR" \
    --field="Название Книги" \
    --field="Автор Книги" \
    --field="Название серии" \
    --field="Номер книги в серии" \
    --field="Читает" \
    --field="Обложка:FL" \
    --field="Конвертировать обложку:CHK" \
    --field="Создавать XML:CHK" \
    --field="Создавать ogg файл:CHK" \
    --field="Средний битрейт:CB" \
    --field="Минимальный битрейт:CB" \
    --field="Максимальный битрейт:CB" \
    --item-separator='|' \
    "$BOOK_NAME" \
    "$AUTHOR_NAME" \
    "$SERIES_NAME" \
    "$SERIES_SEQUENCE" \
    "$NARRATOR_NAME" \
    "$IMAGE_FILE_NAME" \
    $CREATE_COVER \
    $CREATE_XML \
    $CREATE_ONEOGG \
    $BITRATE \
    $MIN_BITRATE \
    $MAX_BITRATE \
    --button="gtk-ok:0" --button="gtk-cancel:1")

if [[ $? -eq 1 ]]; then
  #  cancel button pressed
  exit 192
fi

BOOK_NAME=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $1 }')
BOOK_NAME=$(echo "$BOOK_NAME" | tr '[ ]' '[_]')
AUTHOR_NAME=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $2 }')
AUTHOR_NAME=$(echo "$AUTHOR_NAME" | tr '[ ]' '[_]')
SERIES_NAME=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $3 }')
SERIES_NAME=$(echo "$SERIES_NAME" | tr '[ ]' '[_]')
SERIES_SEQUENCE=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $4 }')
SERIES_SEQUENCE=$(echo "$SERIES_SEQUENCE" | tr '[ ]' '[_]')
NARRATOR_NAME=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $5 }')
NARRATOR_NAME=$(echo "$NARRATOR_NAME" | tr '[ ]' '[_]')
IMAGE_FILE_NAME=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $6 }')
IMAGE_FILE_NAME=$(basename $IMAGE_FILE_NAME)
CREATE_COVER=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $7 }')
CREATE_XML=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $8 }')
CREATE_ONEOGG=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $9 }')
BITRATE=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $10 }')
MIN_BITRATE=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $11 }')
MAX_BITRATE=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $12 }')
BUTTON_OK=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $13 }')
BUTTON_CANSEL=$(echo $TAGS | awk 'BEGIN {FS="|" } { print $14 }')

#----------------------------------------------------------------------
# Сохраняем для отладки
echo "RAW значения формы----------------------------------" > tst.txt
echo $TAGS >> tst.txt
echo "
Разобраные значения формы----------------------------------
BOOK_NAME: $BOOK_NAME
AUTHOR_NAME: $AUTHOR_NAME
SERIES_NAME: $SERIES_NAME
SERIES_SEQUENCE: $SERIES_SEQUENCE
NARRATOR_NAME: $NARRATOR_NAME
IMAGE_FILE_NAME: $IMAGE_FILE_NAME
" >> tst.txt

for arg
do
  NF=$(echo "$arg" | tr '[ ]' '[_]')
  INPUT=$INPUT"|$NF"
  if [ ! "$arg" == "$NF" ]; 
    then 
      if [ -e "$NF" ]; then
        exit_on_error "$NF: File exist already.\n\nExiting."
      fi
      mv "$arg" "$NF"; 
  fi
  NF_DURATION=$(duration $NF)
  IN_DURATION=$(( $IN_DURATION+$NF_DURATION ))
done

INPUT=$(echo "$INPUT" | sed 's/:|/:/')

FFMPEG_CMD="ffmpeg -i \"$INPUT\" \\
-maxrate $MAX_BITRATE -minrate $MIN_BITRATE -ab $BITRATE -acodec $CODEC \\
-metadata title=\"$BOOK_NAME\" \\
-metadata artist=\"$AUTHOR_NAME\" \\
-metadata genre=\"Audiobook\" \\
-metadata album_artist=\"$NARRATOR_NAME\" \\
-metadata album=\"$SERIES_NAME\" \\
-metadata date=\"$DATE\" \\
-metadata track=\"$SERIES_SEQUENCE\" \\
-metadata publisher=\"$PUBLISHER\" \\
-metadata encoded_by=\"$ENCODED_BY\" \\
-metadata copyright=\"$COPYRIGHT\" \\
-metadata composer=\"$COMPOSER\" \\
-metadata performer=\"$PERFORMER\" \\
-metadata disc=\"$DISC\" \\
-metadata encoder=\"$ENCODER\" \\
\"$AUTHOR_NAME-$BOOK_NAME.ogg\""

#----------------------------------------------------------------------
# Сохраняем для отладки
echo "--------------------------------"
echo "Время зввучания: $IN_DURATION сек." >> tst.txt

#----------------------------------------------------------------------
# Для отладки удобно эти команды скинуть в отдельные командные файлы
echo "#!/bin/bash" > ffmpeg_cmd.sh
echo "" >> ffmpeg_cmd.sh
echo "$FFMPEG_CMD" >> ffmpeg_cmd.sh
$(chmod +x ffmpeg_cmd.sh)

echo "#!/bin/bash" > cover_convert_cmd.sh
echo "" >> cover_convert_cmd.sh
echo "convert $IMAGE_FILE_NAME -resize 400x400 $AUTHOR_NAME-$BOOK_NAME.jpg">> cover_convert_cmd.sh
$(chmod +x cover_convert_cmd.sh)

#----------------------------------------------------------------------
# Сконвертируем обложку книги
if [ $CREATE_COVER == "TRUE" ]; then
  RET=$(./cover_convert_cmd.sh)
fi

#----------------------------------------------------------------------
# Сгенерим xml описание книги
if [ $CREATE_XML == "TRUE" ]; then
  echo "
    $BOOK_NAME
    $AUTHOR_NAME
    /sdcard/audiobooks/$AUTHOR_NAME-$BOOK_NAME.jpg
    $SERIES_NAME
    $SERIES_SEQUENCE
    $NARRATOR_NAME
    
        $BOOK_NAME 
        
    
    
        /sdcard/audiobooks/$AUTHOR_NAME-$BOOK_NAME.ogg
    
" > $AUTHOR_NAME-$BOOK_NAME.xml
fi

#----------------------------------------------------------------------
# Собственно, запуск конвертирования
if [ $CREATE_ONEOGG == "TRUE" ]; then
  touch /tmp/$$
  ( ( echo 1 
      while [ -f /tmp/$$ ] 
        do 
          sleep 10
   # Вычисления процента сконвертированного
          OUT_DURATION=$(duration "$AUTHOR_NAME-$BOOK_NAME.ogg")
          PERCENTAGE=$(( OUT_DURATION*100/IN_DURATION))
          echo $PERCENTAGE
        done
      echo 100 ) | yad --title "$CURENT_DIR" \
                     --progress \
                     --progress-text="$AUTHOR_NAME-$BOOK_NAME.ogg" \
                     --percent=0 --auto-close --no-buttons --width=300) &
  RET=$(./ffmpeg_cmd.sh)
  rm /tmp/$$
  wait
fi

#----------------------------------------------------------------------
# Конец
yad --no-wrap \
   --title "Конвертирование завершено" \
   --text "$CURENT_DIR/$AUTHOR_NAME-$BOOK_NAME.ogg"

rm ./cover_convert_cmd.sh
rm ./ffmpeg_cmd.sh
rm ./tst.txt


Если захотите ей воспользоваться, то сохрание ее в ~/.local/share/nautilus/scripts/merge_mp3.sh. После чего дайт права на исполнение следующей командой.
chmod +x ~/.local/share/nautilus/scripts/merge_mp3.sh
Кроме того необходимо установить пакеты yad и python-mutagen

Пользоваться ей очень просто. Сначала в Nautilus выделяю файлы книги, которые хочу объединить.




Затем нажимаю правую кнопку и выбираю скрипт:




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




Наблюдаем за ходом конвертирования



Дизастер! Оказалось, что в Android плохая реализация проигрывания ogg файлов с переменным битрейтом. Плеер не может точно позиционировать на выбранное место. Выглядит это так: вы выставляете проигрывание с позиции 1 час 28 мин 33 сек. Плеер передвигает вперед минут на 20 и начинает воспроизведение. За это я господ их Гугле материл. Бороться с этим можно только установив при кодировании постоянный битрейт.

Для книги вполне достаточно битрейта 96 к.


Полезные ссылки:
1. Кодирование аудио с потерями. Что к чему?
2. mutagen

среда, 22 августа 2012 г.

Linux. How to delete duplicate images 2?

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

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

Более эффективно воспользоваться существующими инструментами, например мощной программой управления фотоколлекцией DigiKam.

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

Я провел небольшое расследование и обнаружил, что результаты поиска дубликатов сохраняются в базе данных, которая обычно располагается в $HOME/Pictures/digikam4.db

Как DigiKam сохраняет результаты поиска я покажу на следующем примере.

Есть папка с изображениями.
В программе digikam запускаем поиск одинаковых изображений.

Результаты поиска сохраняются в таблице searches. Эта таблица содержит строки с результатами поиска.


Каждая строка в поле query хранит xml список содержащий id одинаковых изображений. На приведенном листинге я отформатировал xml, чтобы удобней его было читать.


 
  
   3
   2 
   1
  
 


Имена файлов изображений хранятся в таблице images и доступны по id


Путь доступен по полю (номер альбома) в таблице albums:


Путь к альбомам хранится в таблице albumroot:


Ниже пример реализации функции на bash получения пути изображения с id = 5
#!/bin/bash 

DBPATH=digikam4.db 

getPicture () 
{ 
  FILENAME=$(sqlite3 $DBPATH "SELECT name FROM images WHERE id=$1") 
  IDALBUM=$(sqlite3 $DBPATH "SELECT album FROM images WHERE id=$1") 
  REALTIVEPATH=$(sqlite3 $DBPATH "SELECT relativePath FROM albums WHERE id=$IDALBUM") 
  IDALBUMROOT=$(sqlite3 $DBPATH "SELECT albumRoot FROM albums WHERE id=$IDALBUM") 
  ROOTPATH=$(sqlite3 $DBPATH "SELECT specificPath FROM albumroots WHERE id=$IDALBUMROOT") 
  echo /home/${ROOTPATH}/${REALTIVEPATH}/${FILENAME} 
} 

FNAME=$(getPicture 5) 
echo $FNAME 

Ну, собственно, вот и венец творений.
Программа на bash, которая удаляет дубликаты изображений.
Программа удаляет дубликат меньшего размера.
Я ее успешно использую совместно с DigiKam 2.8 под Ubuntu.
Перед запуском скрипта нужно выйти из DigiKam, иначе скрипт не может получить доступ к базе, которая лочится.
#!/bin/bash
#-------------------------------------------------------------------
# Удаляет дубликаты картинок на основании поиска дубликатов в 
# программе DigiKam
#
# Проверено с DigiKam v2.8
COPYRUGHT="\n© http://axa-ru.blogspot.com. Licensed under GPLv3."

#-------------------------------------------------------------------
#VERSION=0.1 # initial version
#VERSION=0.11 # Some DeBugs
#VERSION=0.12 # Добавлено приоритет удаления
#VERSION=0.13 # Some changes
VERSION=0.14 # Испрвавление ошибки в delSmallPic()

DEBUG=0
VERBOSE=1
DBPATH=$HOME/Pictures/digikam4.db # Путь до базы даннх DigiKam
EXITERROR=192

SAVEPIC=""
PATTERN=0_WallPapers99

# Color ANSY sequence
BLACK="\033[0;30m"
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
MAGENTA="\033[0;35m"
CYAN="\033[0;36m"
WHITE="\033[0;37m"
GRAY1="\033[38;5;252m"
GRAY2="\033[38;5;245m"
GRAY3="\033[38;5;238m"
NOCOLOR="\033[0;38m"

#-------------------------------------------------------------------
#  Возвращает по id изображения его полный путь
#  пример использования:
#     FNAME=$(getPicture 1653)
#  возвращает путь к картинке №1653

getPicture ()
{
  FILENAME=$(sqlite3 $DBPATH "SELECT name FROM images WHERE id=$1")
  IDALBUM=$(sqlite3 $DBPATH "SELECT album FROM images WHERE id=$1")
  REALTIVEPATH=$(sqlite3 $DBPATH "SELECT relativePath FROM albums WHERE id=$IDALBUM")
  IDALBUMROOT=$(sqlite3 $DBPATH "SELECT albumRoot FROM albums WHERE id=$IDALBUM")
  local ALBUM_TYPE=$(sqlite3 $DBPATH "SELECT type FROM albumroots WHERE id=$IDALBUMROOT")
  case $ALBUM_TYPE in
    1) ROOTPATH=/home$(sqlite3 $DBPATH "SELECT specificPath FROM albumroots WHERE id=$IDALBUMROOT");;
    2) echo "External media not supported yet. Exiting"; exit $EXITERROR;;
    3) ROOTPATH=$(sqlite3 $DBPATH "SELECT identifier FROM albumroots WHERE id=$IDALBUMROOT" | sed 's/networkshareid:?mountpath=//g' | sed 's/%2F/\//g');;
  esac  

  echo ${ROOTPATH}/${REALTIVEPATH}/${FILENAME}
}

#-------------------------------------------------------------------
#  Удаляет меньшую картинку из двух
#  
delSmallPic()
{
  ((DEBUG)) && echo "    ***** $FUNCNAME"

  if [ "$SAVEPIC" == "" ]; then 
    #((DEBUG)) && echo "    $LINENO: Init SAVEPIC"
    SAVEPIC="$1";
  else
    local W0=$(identify -format '%w' "$SAVEPIC" 2> /dev/null)
    local H0=$(identify -format '%h' "$SAVEPIC" 2> /dev/null)
    local W1=$(identify -format '%w' "$1" 2> /dev/null)
    local H1=$(identify -format '%h' "$1" 2> /dev/null)

    ((DEBUG)) && echo "    $LINENO: PIC1=$SAVEPIC"
    ((DEBUG)) && echo "    $LINENO: PIC2=$1"
    ((DEBUG)) && echo "    $LINENO: $W0 -eq $W1 -a $H0 -eq $H1"

    # Если картинки одинаковы то удаляет ту, в пути (имени)
    # которой есть $PATTERN
    if [ $W0 -eq $W1 -a $H0 -eq $H1 ]; then
      ((DEBUG)) && echo "    $LINENO: PIC1 == PIC2"
      if [[ "$SAVEPIC" =~ .*$PATTERN.* ]]; then
        echo "Delete $SAVEPIC"
        ((DEBUG)) && printf "    %s: " $LINENO
        ! ((DEBUG)) && rm "$SAVEPIC"
        SAVEPIC="$1"
      else
        ((DEBUG)) && printf "    %s: " $LINENO
        echo "Delete $1"
        ! ((DEBUG)) && rm "$1"
      fi
    else 
      if [ $W0 -le $W1 -o $H0 -le $H1 ]; then
        ((DEBUG)) && echo "    $LINENO: PIC1 <= PIC2"
        echo "Delete $SAVEPIC"
        ((DEBUG)) && printf "    %s: " $LINENO
        ! ((DEBUG)) && rm "$SAVEPIC"
        SAVEPIC="$1"
      else
        ((DEBUG)) && echo "    $LINENO: PIC1 > PIC2"
        ((DEBUG)) && printf "    %s: " $LINENO
        echo "Delete $1"
        ! ((DEBUG)) && rm "$1"
      fi    
    fi
  fi
}

#-------------------------------------------------------------------
#  Удаляет дубликаты картинок из списка
#  В качестве параметра получает список id картинок с разделителями пробелами
delDupPic ()
{
  while (( "$#" )); do
    local PAR=$1
    PICURL=$(getPicture "$PAR")
    if [ ! -f $PICURL ]; then
      echo -e "${RED}File $PICURL das not exists.${NOCOLOR}"
      # echo -e "${RED}Use digiKam!!!${NOCOLOR}"
      # exit $EXITERROR
    fi
    ((DEBUG)) && echo "  $LINENO: PAR=$PAR, PICURL=$PICURL"
    delSmallPic $PICURL
    shift
  done
}

#-------------------------------------------------------------------
#  main code
#

  while getopts "Dd:hVv" SWITCH ; do
    case $SWITCH in
      D) DEBUG=1;;
      d) if [[ $OPTARG == "" ]]; then 
           printf "$SCRIPT:$LINENO: must be argument\n"; 
           exit $ERROR; 
         else 
           PATTERN=$OPTARG; 
         fi;;
      h) echo -e "usage: 
  ${CYAN}$0 [-OPTION]${NOCOLOR}

    OPTION is
    ${CYAN}D${NOCOLOR}       - Debug On
    ${CYAN}d [PAT]${NOCOLOR} - Delete first pic by PATtern
                Example: 
                 deldup.sh -d 00_Picture 
                will delete any picture
                 /mnt/nas3d0/Pictures/Wallpaper/00_Pictures/Pictures_0123.jpg 
    ${CYAN}h${NOCOLOR}       - This help
    ${CYAN}v${NOCOLOR}       - Verbose output, No output by default"
        exit 0
        ;;
      V) echo -e "${CYAN}$0 Version $VERSION\n${COPYRUGHT}${NOCOLOR}"; exit 0;;
      v) VERBOSE=1;;
      *) printf "$SCRIPT:$LINENO: script error: unhandled argument\n"; exit $ERROR;;
    esac
  done


((DEBUG)) && echo "$LINENO: TOTAL=$TOTAL"

# Type=7 - записи после операции поиска дубликатов
X=$(sqlite3 $DBPATH "SELECT id FROM searches where type=7 LIMIT 1")
TOTAL=$(sqlite3 $DBPATH "SELECT COUNT (*) FROM searches WHERE type=7")
echo "$TOTAL Duplicate Images Will be Delete "
((LAST=TOTAL+X))
((DEBUG)) && echo "$LINENO: X=$X, LAST=$LAST, TOTAL=$TOTAL"

while [ $X -lt $LAST ]
do
  SAVEPIC=""
  # Получаем список записей с дублированными картинками 
  # Ниже показан отформатированный пример. 
  # 
  # 
  #   
  #     
  #       5033
  #       201
  #       84132
  #     
  #   
  # 
  LISTEQPIC=$(sqlite3 $DBPATH "SELECT query FROM searches WHERE id=$X" | sed 's/<\/listitem>/,/g' | sed 's///g' | sed 's/.*oneof\">//' | sed 's/,<\/.*//' | sed 's/,/ /g' )
  ((DEBUG)) && echo "$LINENO: X=$X, LISTEQPIC=$LISTEQPIC"
  delDupPic $LISTEQPIC
  ((X++))
done

По хорошему этот скрипт можно оформить в виде плагина в DigiKam и запускать оттуда. Будет функциональней и удобней. Но мне лень ковырять сам DigiKam. Если кто сделает такое добро, то отпишите.


Полезные ссылки:

суббота, 11 августа 2012 г.

How to delete old kernels

Очень просто.
Я сохранил скрипт под именем del_old_kernels.sh

#!/bin/bash 
for K in $(ls /boot/ | grep vmlinuz | sed 's@vmlinuz-@linux-image-@g' | grep -v `uname -r`)
do
  aptitude remove $K
done
update-grub
Затем дал права скрипту на исполнение, установил aptitude и запустил скрипт.

chmod +x del_old_kernels.sh sudo apt-get install aptitude sudo ./del_old_kernels.sh

Полезные ссылки:

воскресенье, 3 июня 2012 г.

Шрифты Win7 в Ubuntu

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

Чтобы в пакетах LibreOffice тексты отображались так же как и в MS Office нужно, как минимум, установить шрифты от windows идущие в стандартной поставке.
Кроме того в Ubuntu стоят маловостребованные на территории России китайские, малайские и иже с ними шрифты.

Я удалил китайские-малайские шрифты:
sudo apt-get remove ttf-indic-fonts-core ttf-kacst-one ttf-khmeros-core ttf-lao ttf-punjabi-fonts ttf-takao-pgothic ttf-thai-tlwg ttf-unfonts-core ttf-wqy-microhei fonts-kacst fonts-kacst-one fonts-khmeros-core fonts-lao fonts-takao-pgothic fonts-thai-tlwg fonts-tlwg-garuda fonts-tlwg-kinnari fonts-tlwg-loma fonts-tlwg-mono fonts-tlwg-norasi fonts-tlwg-purisa fonts-tlwg-sawasdee fonts-tlwg-typewriter fonts-tlwg-typist fonts-tlwg-typo fonts-tlwg-umpush fonts-tlwg-waree fonts-nanum
Затем удалил неполные пакеты шрифтов: sudo apt-get remove ttf-dejavu-core ttf-dejavu-extra fonts-liberation ttf-liberation
Затем скачал и установил пакет с русскими шрифтами от Windows 7: cd /tmp wget https://www.opendrive.com/files/57831796_SiIyc_8fa4/win7-rus-fonts_0.0.10_all.deb sudo dpkg -i win7-rus-fonts_0.0.10_all.deb
Вуаля, а ни какая не виола.

четверг, 16 февраля 2012 г.

Банальные флаги раскладки Ubuntu

Я уже запарился каждый раз рисовать или отыскивать флаги раскладки клавиатуры для Ubuntu.
Чтобы больше не париться решил положить их здесь в блоге. Может кому пригодятся тоже.
Скачать: тыц.

Поставить можно так: $ mkdir -p ~/.icons/flags $ cd ~/.icons/flags $ wget https://od.lk/d/58719109_khKg0/flags.tar.gz $ tar xzvf flags.tar.gz $ gsettings set org.gnome.libgnomekbd.indicator show-flags true Затем нужно перелогиниться или перезагрузиться.

Для выбора соответствующего набора флагов можно запустить скрипт, из архива: $ cd ~/.icons/flags $ ./sf 01 где 01 - номер набора от 01 до 15.


07/05/2012 - добавил в архив индикаторы раскладки для Gnome 3
01/07/2012 - обновил архив до 15 иконок

среда, 25 января 2012 г.

Не монтируется CD-RW в Ubuntu

У меня бывали случаи, что некоторые CD-RW диски переставали монтироваться. Происходило это либо после ошибки записи, либо еще по какой причине. Я обычно не разбирался долго, а просто выбрасывал такую болванку и брал новую.

На самом деле CD-RW, который не монтируется можно попытаться восстановить. Для этого нужно восстановить на нем файловую структуру.

В два приема:
  1. Определим куда подключено устройство: $ cdrecord -scanbus scsibus6: 6,0,0 600) 'TSSTcorp' 'CDDVDW SN-S082N ' 'LA00' Removable CD-ROM 6,1,0 601) * 6,2,0 602) * 6,3,0 603) * 6,4,0 604) * 6,5,0 605) * 6,6,0 606) * 6,7,0 607) *
  2. Затем даем команду стирания CD-RW. В качестве параметра dev подставляем адрес 6,0,0 , который определился выше. $ sudo cdrecord blank=all -force dev=6,0,0 И примерно через 8-16 минут (В зависимости от максимальной скорости привода) получаем сообщение от системы, что диск смонтирован
Теперь можно на него записывать иcкоробочной программой Brothero.


Полезные ссылки:

понедельник, 9 января 2012 г.

Настройка энергопотребления ThinkPad x220 в Ubuntu 12.04

Куратор темы на ixbt о ноутбуке ThinkPad x220 попросил написать меня статью об оптимизации потребления на ThinkPad x220, что я и сделал.
На мой взгляд статья получилась хорошей, но ixbt устроен так, что я не могу делать там обновления.
Поэтому я публикую ее в моем блоге. Здесь будут вноситься изменения, если таковые появятся.
А когда будет время поправлю структуру и ссылки в основной статье об экономии электричества в линуксе.

На все про все, если вы делаете это в первый раз, запаситесь примерно 2-мя часами.

Потребление замеряется в idle и с уровнем подсветки дисплея 20%. Когда систему "успокоилась" и переходные процессы завершены.

Каждый раздел оптимизации не зависит от другого и может быть применен отдельно.

  1. Установка и настройка pm-utils
    1. Установить необходимые программы: apmd, pm-utils и т.п. $ sudo apt-get install apmd pm-utils hdparm libnotify-bin
    2. Создадим скрип управления энергопотреблением: $ sudo gedit /usr/lib/pm-utils/power.d/99-savings.sh В появившемся окне редактора копипастим следующий текст
      ######################################################################################
      # A script to aggressively toggle power management between high 
      # performance and very low power consumption.
      # For more information on each of these options, see http://www.lesswatts.org
      # Last version script see http://axa-ru.blogspot.com/2012/01/thinkpad-x220-powersaving.html
      ################# Changes history ###################################################
      #VERSION=0.12   # 31.08.2010 Testing Ubuntu 10.04. Small changes for Wi-Fi control
      #VERSION=0.13   # 21.09.2010 Adding services control: 
                      #   evolution-alarm-notify, 
                      #   postfix, 
                      #   rsyslog
      #VERSION=0.2    # 23.07.2011 Modified for Ubintu 11.04 for Thinkpad x220 4290rw1
      #VERSION=0.23   # 27.07.2011 Added store value (Brightness, user, etc ) to /tmp/powersave.ini
                      #   Fix notify-send message
                      #   Added CPU core disabling. Disable cores not affected for power saving
      #VERSION=0.23.1 # 07.01.2012 Fix ethtool parameters in aLan procedure
                      #     
      #VERSION=0.23.2 # 07.01.2012 Fix aBrightness procedure
      VERSION=0.24    # 08.01.2012 Added start/stop conky monitor
      
      #
      # To install:
      #
      # sudo apt-get install apmd pm-utils expect hdparm libnotify-bin
      #
      # Save this file to /usr/lib/pm-utils/power.d/99-savings.sh
      # cd /usr/lib/pm-utils/power.d
      # sudo install 99-savings.sh /etc/pm/sleep.d
      # sudo install 99-savings.sh /etc/pm/power.d
      #
      
      INI_DIR=/tmp
      INI_FILE=powersave.ini
      INI=${INI_DIR}/${INI_FILE}
      
      aUsb()
      {
        #################################################
        ## USB Subsystem
        ##
        # 0.7-0.8 W
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/usb/devices/*/power/control
            do
              echo "on" > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/usb/devices/*/power/control
            do
              echo "auto" > $i
            done
      
            for i in /sys/bus/usb/devices/*/power/autosuspend
            do
              echo 1 > $i
            done
      
            echo 1 > /sys/module/usbcore/parameters/autosuspend
            ;;
        esac
      }
      
      aSata()
      {
        case "$1" in
          false)  #ac_power
            # Set the SATA to max performance
            for i in /sys/class/scsi_host/host*/link_power_management_policy
            do
              echo max_performance > $i
            done
            ;;
      
          true)  #batt_power
            # Set SATA to minimum power
            # 0.7 W
            for i in /sys/class/scsi_host/host*/link_power_management_policy
            do
              echo min_power > $i
            done
            ;;
        esac
      }
      
      aPci()
      {
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/pci/devices/*/power/control
            do
              echo on > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/pci/devices/*/power/control
            do
              echo auto > $i
            done
            ;;
        esac
      }
      
      aI2c()
      {
        case "$1" in
          false)  #ac_power
            for i in /sys/bus/i2c/devices/i2c-*/power/control
            do
              echo on > $i
            done
            ;;
      
          true)  #batt_power
            for i in /sys/bus/i2c/devices/i2c-*/power/control
            do
              echo auto > $i
            done
            ;;
        esac
      }
      
      aHdd()
      {
        case "$1" in
          false)  #ac_power
            # Set the drive to mostly stay awake.  Some may want to change -B 200
            # to -B 255 to avoid accumulating Load_Cycle_Counts
            # -S 240 => put in standby after 20 minutes idle
            # -B 200 => do not permit spindown
            # -M => not supported by my drive
            hdparm -B 200 -S 240 -M 254 /dev/sda
      
            # Remount ext3/4 filesystems so the journal commit only happens every 60
            # seconds.  By default this is 5 but, I prefer to reduce the disk
            # activity a bit.
            mount -o remount,commit=60,atime /
            ;;
      
          true)  #batt_power
            hdparm -B 1 -S 4 -M 128 /dev/sda
            mount -o remount,noatime,commit=600 /
      
            ;;
        esac
      }
      
      aSsd()
      {
      
      # add these commands in the /etc/rc.local
      #  echo deadline > /sys/block/sda/queue/scheduler
      #  echo 1 > /sys/block/sda/queue/iosched/fifo_batch
      #  sysctl -w vm.swappiness=1            # Strongly discourage swapping
      #  sysctl -w vm.vfs_cache_pressure=50   # Don't shrink the inode cache aggressively
        case "$1" in
          false)  #ac_power
            ;;
      
          true)  #batt_power
            ;;
        esac
      }
      
      aI915()
      {
        case "$1" in
          false)  #ac_power
            echo 0 > /sys/module/i915/parameters/powersave
            ;;
      
          true)  #batt_power
            echo 1 > /sys/module/i915/parameters/powersave
            ;;
        esac
      }
      
      aWlan()
      {
            # WiFi power savings.
        case "$1" in
          false)  #ac_power
            /sbin/iwconfig wlan0 power off txpower 14
            ;;
      
          true)  #batt_power
            /sbin/iwconfig wlan0 power on txpower 4
            ;;
        esac
      }
      
      aLan()
      {
        case "$1" in
          false)  #ac_power
            # set the ethernet max speed.
            ethtool -s eth0 speed 1000 duplex full autoneg on wol d
            ;;
          true)  #batt_power
            # set the ethernet power savings.
            # ~ 0.4 W
            ethtool -s eth0 speed 10 duplex half autoneg off wol d
            ;;
        esac
      }
      
      aCpu()
      {
        #################################################
        ## CPU
        ##
      
        case "$1" in
          false)  #ac_power
            for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
            do
              echo performance > $i
            done
      
            # Enable All Core CPU
            for i in /sys/devices/system/cpu/cpu*/online
            do
              echo 1 > $i
            done
      
            # Set max freq 2.7 GHz
      #      for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
      #      do
      #        echo 2701000 > $i
      #      done
      
            # Shedule Multitreading
            echo 0 > /sys/devices/system/cpu/sched_mc_power_savings
            ;;
      
          true)  #batt_power
            for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
            do
              echo powersave > $i
            done
      
            # Set max freq 1 GHz
      #      for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
      #      do
      #        echo 1000000 > $i
      #      done
      
      #      Disable cores not affected for power saving
      #      for i in /sys/devices/system/cpu/cpu*/online
      #      do
      #        echo 0 > $i
      #      done
      
            echo 1 > /sys/devices/system/cpu/sched_mc_power_savings
            ;;
        esac
      }
      
      aSnd()
      {
        case "$1" in
          false)  #ac_power
            echo 0 > /sys/module/snd_hda_intel/parameters/power_save
            ;;
      
          true)  #batt_power
            # Turn off sound card power savings
            # < 0.1 W
            echo 10 > /sys/module/snd_hda_intel/parameters/power_save
            ;;
        esac
      }
      
      aBt()
      {
        case "$1" in
          false)  #ac_power
            # Enable the bluetooth driver
            rfkill unblock bluetooth
            ;;
      
          true)  #batt_power
            # Remove the bluetooth driver
            # 0.3-0.4 W
            rfkill block bluetooth
            ;;
        esac
      }
      
      aDaemons()
      {
        #################################################
        ## demons, services
        ##
      
        case "$1" in
          false)  #ac_power
            # 1. Evolution alarm and integrations
            /usr/lib/evolution/2.32/evolution-alarm-notify &
            #/usr/lib/evolution/e-calendar-factory &
            #/usr/lib/evolution/e-addressbook-factory &
      
            # 2. Starting Sendmail server 
            #postfix start 
      
            # 3. Starting CouchDB & desktopcouch
            dbus-send --session --dest=org.desktopcouch.CouchDB --print-reply --type=method_call / org.desktopcouch.CouchDB.getPort
      
            # 4. Starting conky
            if [ ${CONKY_RUN} -eq 1 ]; then
              su $vUSER -c "/usr/bin/conky --display=:0 &"
            fi
            ;;
      
          true)  #batt_power
            # 1. Evolution alarm
            killall evolution-alarm-notify
            #killall e-calendar-factory
            #killall e-addressbook-factory
      
            # 2. Stopping Sendmail server 
            #postfix stop
      
            # 3. Stoping CouchDB & desktopcouch
            killall beam.smp
            killall desktopcouch-service
      
            # Stoping conky ~1W
            killall conky
            ;;
        esac
      }
      
      # < 0.1 W
      aWebcam()
      {
        case "$1" in
          false)  #ac_power
            # Enable the webcam driver
            modprobe uvcvideo
            ;;
      
          true)  #batt_power
            # Remove the webcam driver
            modprobe -r uvcvideo
            ;;
        esac
      }
      
      aMemory()
      {
        case "$1" in
          false)  #ac_power
            # Set kernel dirty page value back to default
            echo 10 > /proc/sys/vm/dirty_ratio
            echo 5 > /proc/sys/vm/dirty_background_ratio
      
            # Only wakeup every 60 seconds to see if we need to write dirty pages
            # By default this is every 5 seconds but, I prefer 60 to reduce disk
            # activity.
            echo 6000 > /proc/sys/vm/dirty_writeback_centisecs
            ;;
      
          true)  #batt_power
            # Reduce disk activity by waiting up to 10 minutes before doing writes
            echo 90 > /proc/sys/vm/dirty_ratio
            echo 1 > /proc/sys/vm/dirty_background_ratio
            echo 60000 > /proc/sys/vm/dirty_writeback_centisecs
            ;;
        esac
      }
      
      aBrightness()
      {
        case "$1" in
          false)  #ac_power
            # Setup maximum brigthness
            # Thinkpad x220, Ubuntu 11.04
            vBAT_BRI=$(cat /sys/class/backlight/acpi_video0/brightness)
            echo $vAC_BRI > /sys/class/backlight/acpi_video0/brightness
            ;;
      
          true)  #batt_power
            # Setup brigthness 30%
            vAC_BRI=$(cat /sys/class/backlight/acpi_video0/brightness)
            echo $vBAT_BRI > /sys/class/backlight/acpi_video0/brightness
            ;;
        esac
      }
      
      aMisk()
      {
        case "$1" in
          false)  #ac_power
            # Turn off the laptop mode disk optimization
            echo 0 > /proc/sys/vm/laptop_mode
            echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource
      
            # enable logging
            service rsyslog start
      
            # ZiXEL nbg460n. Set maximum wifi speed
            if [ -f /etc/pm/802.11.bgn ]; then /etc/pm/802.11.bgn 1; fi
      
            # enable winbind
            if [ -f /etc/init.d/winbind ]; then  /etc/init.d/winbind start; fi
      
            # Powersave pci express
            echo performance > /sys/module/pcie_aspm/parameters/policy
            ;;
      
          true)  #batt_power
            # Set laptop disk write mode
            echo 5 > /proc/sys/vm/laptop_mode
            echo hpet > /sys/devices/system/clocksource/clocksource0/current_clocksource
            # disable logging
            service rsyslog stop
      
            # ZiXEL nbg460n. Set standard wifi speed
            if [ -f /etc/pm/802.11.bgn ]; then /etc/pm/802.11.bgn 0; fi
      
            # disable winbind
            if [ -f /etc/init.d/winbind ]; then  /etc/init.d/winbind stop ; fi
      
            echo powersave > /sys/module/pcie_aspm/parameters/policy
            ;;
        esac
      }
      
      aNotify()
      {
        case "$1" in
          false) #ac_power
            MSGH="AC" 
            MSGT="Maximum Performance Mode"
            MSGI="ac-adapter"
            ;;
          true)  #battery_power 
            MSGH="BATT" 
            MSGT="Battery Power Saving"
            MSGI="battery"
          ;;
        esac
      
        vUSER=`ps -C gnome-session -o user=` #find UID user who start gnome-session
        vPIDS=`pgrep -u $vUSER gnome-session` #find PID
        for PID in $vPIDS; do
          vDBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ \
          | sed -e 's/DBUS_SESSION_BUS_ADDRESS=//')
          DBUS_SESSION_BUS_ADDRESS=$vDBUS_SESSION_BUS_ADDRESS DISPLAY=:0.0 sudo -u $vUSER notify-send "$MSGH" "$MSGT" -i "$MSGI"
        done
      }
      
      aLoadini()
      {
        if [ -e $INI ]; 
          then 
            echo "Restore Value"
            while read LINE
            do
              PARM=$(echo "$LINE" | awk '{print $1}')
              KEY=$(echo "$LINE" | awk '{print $2}')
              case $PARM in
                "AC_BRI")
                  vAC_BRI=$KEY
                  ;;
                "BAT_BRI")
                  vBAT_BRI=$KEY
                  ;;
                "USER")
                  vUSER=$KEY
                  ;;
                "PIDS")
                  vPIDS=$KEY
                  ;;
                "CONKY")
                  CONKY_RUN=$KEY
                  ;;
                "DBUS_SESSION_BUS_ADDRESS")
                  vDBUS_SESSION_BUS_ADDRESS=$KEY
                  ;;
              esac
              echo "$PARM $KEY"
            done < $INI
          else
            echo "Reset Value"
            # Conky is Running Check
            CONKY_RUN=$(ps -ef | grep -c /usr/bin/conky)
            ((CONKY_RUN-=1))
      
            vAC_BRI=15
            vBAT_BRI=8
            vUSER=""
            vPIDS=""
            vDBUS_SESSION_BUS_ADDRESS=""
        fi
      }
      
      aSaveini()
      {
        echo "AC_BRI $vAC_BRI" > $INI
        echo "BAT_BRI $vBAT_BRI" >> $INI
        echo "USER $vUSER" >> $INI
        echo "PIDS $vPIDS" >> $INI
        echo "CONKY $CONKY_RUN" >> $INI
        echo "DBUS_SESSION_BUS_ADDRESS $vDBUS_SESSION_BUS_ADDRESS" >> $INI
      }
      
      
      ##########################################################
      ## Apply settings
      ##
      aLoadini
      
      aCpu $1
      aUsb $1
      aI2c $1
      aSata $1
      aPci $1
      if [ $(hdparm -i /dev/sda | grep Model | awk '{print substr($2,1,3)}') = "SSD" ]; 
        then 
          aSsd $1
        else
          aHdd $1
      fi
      aI915 $1
      aWlan $1
      aLan $1
      aSnd $1
      aBt $1
      aWebcam $1
      aMemory $1
      aDaemons $1
      aBrightness $1
      aMisk $1
      aNotify $1
      
      aSaveini
      

      Сохраняем скрипт и закрываем редактор
    3. Подключаем скрипт к событиям power и sleep $ cd /usr/lib/pm-utils/power.d $ sudo chmod 755 99-savings.sh $ sudo install 99-savings.sh /etc/pm/sleep.d $ sudo install 99-savings.sh /etc/pm/power.d
    4. Проверяем
      Вытаскиваем провод источника питания и наблюдаем pop up сообщение, что компьютер перешел в режим сохранения энергии Вставяем провод источника питания и наблюдаем pop up сообщение, что компьютер перешел в режим максимального быстродействия

  2. Устанавливаем ядро 3.63.3.7
  3. У меня иногда с ядром 3.6 процессор переходит в Turbo mode и начинает сильно нагреваться. Powertop показывает частоту 3 GHz. htop не показывает никакого криминала. А процессоры находятся в состоянии powersave. Разбираюсь. Возможно это баг.
    Если у вас будет то же самое отпишите, плз.

    Можно не мудрствуя лукаво поставить из http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/ if [ ! -d "$HOME/kernel" ]; then mkdir $HOME/kernel; fi cd "$HOME/kernel" rm *.deb wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-headers-3.3.7-030307-generic_3.3.7-030307.201205211535_amd64.deb \ http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-headers-3.3.7-030307_3.3.7-030307.201205211535_all.deb \ http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.3.7-precise/linux-image-3.3.7-030307-generic_3.3.7-030307.201205211535_amd64.deb sudo dpkg -i *.deb

  4. Устанавливаем параметры загрузки Ubuntu в Grub
  5. В терминале с помощью редактора gedit $ sudo gedit /etc/default/grub Заменяем строку
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
    
    на
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i915.i915_enable_rc6=1 i915.lvds_downclock=1 i915_enable_fbc=1 drm.vblankoffdelay=1 pcie_aspm=force reboot=pci"
    
    Обновляем grub $ sudo update-grub Перезагружаемся и проверяем энергопотребление.

  6. Success Story

  7. Евгений Попов прислал скриншот, на котором видно, что он смог снизить минимальное потребление до 4,77 Вт (Lenovo ThinkPad x220 4290RW1, Ubuntu 11.10).

    Участник с ником unr форума Ubuntu получил потребление около 5,5 Вт на ядре 3.2.5 (Lenovo ThinkPad x220 4290RW1, Ubuntu 11.10).


  8. Indicator

  9. Я самоуверенно дал программе название, которое уже присвоено другой утилите. К выходным переобзову и сделаю новый deb пакет.

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

    Остальные пункты меню представляют собой заглушки. Надеюсь скоро их активизирую.
    Скачать индикатор можно по ссылке: powerman_0.1_amd64.deb
    Устанавливается, как обычный deb пакет. sudo dpkg --install powerman_0.1_amd64.deb После чего можно добавить запуск индикатора в Startup Applications:
    /usr/bin/powerman -t 10
    
    где -t 10 задает время задержки старта.

    И последним штрихом добавляем в sudoers команды, разрешающие запуск скрипта управления питанием без ввода пароля. sudo visudo
    # User alias specification
    # Change %axa to your Users Grup. Замените %axa на название группы, куда входит пользователь
    User_Alias USERS = %axa
    
    # Cmnd alias specification
    Cmnd_Alias PWR_SAVE =  /etc/pm/power.d/99-savings.sh
    
    # All User can run Power Saving script
    USERS ALL=NOPASSWD: PWR_SAVE
    

  10. Планы на развитие
  11. В планах убрать установку всех скриптов и модификацию управляющих файлов внутрь deb пакета.

Полезные ссылки:



03.10.2012 - добавил раздел установки индикатора
06.10.2012 - временно убрал раздел компиляции ядра и добавил раздел установки ядра 3.6 из ubuntu.kernel