User Tools

Site Tools


Sidebar


Tags Cloud
start

This is an old revision of the document!


Table of Contents

Last updates

Использование chroot для sftp подключений

# mkdir -p /srv/ssh/chroot
# mkdir -p /etc/ssh/authorized_keys /srv/ssh/chroot
# groupadd sftponly
# useradd -G www-data -g sftponly -s /usr/sbin/nologin -d /srv/ssh -N USERNAME
# find /var/www/static -type d -print0 | xargs -0 chmod g+xwr
# find /var/www/static -type f -print0 | xargs -0 chmod g+wr
# chmod 775 /var/www/static /srv/ssh/chroot
# mount -o bind /var/www/static /srv/ssh/chroot
/etc/ssh/sshd_config
Subsystem sftp internal-sftp -u 0002
AuthorizedKeysFile /etc/ssh/authorized_keys/%u %h/.ssh/authorized_keys .ssh/authorized_keys
Match Group sftponly
  ChrootDirectory %h
  ForceCommand internal-sftp -u 0002
  AllowTcpForwarding no
  X11Forwarding no
  PasswordAuthentication no
/etc/fstab
LABEL=cloudimg-rootfs   /               ext4  defaults,discard  0 0
/var/www/static         /srv/ssh/chroot none  bind              0 0
2018/05/10 16:05 · kyxap

Apache-like ~/public_html access

2016/03/13 22:02 · kyxap

ffmpeg-php centos 6.x

atrpms-repo-6-7.el6.x86_64 https://www.mirrorservice.org/sites/dl.atrpms.net/el$releasever-$basearch/atrpms/stable

atrpms.repo
[atrpms]
name=Red Hat Enterprise Linux $releasever - $basearch - ATrpms
failovermethod=priority
#baseurl=http://dl.atrpms.net/el$releasever-$basearch/atrpms/stable
baseurl=https://www.mirrorservice.org/sites/dl.atrpms.net/el$releasever-$basearch/atrpms/stable
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-atrpms
 
[atrpms-debuginfo]
name=Red Hat Enterprise Linux $releasever - $basearch - ATrpms - Debug
failovermethod=priority
baseurl=https://www.mirrorservice.org/sites/dl.atrpms.net/debug/el$releasever-$basearch/atrpms/stable
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-atrpms
 
[atrpms-source]
name=Red Hat Enterprise Linux $releasever - $basearch - ATrpms - Source
failovermethod=priority
baseurl=https://www.mirrorservice.org/sites/dl.atrpms.net/src/el$releasever-$basearch/atrpms/stable
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-atrpms
#!/usr/bin/env bash

yum --enablerepo=atrpms ffmpeg-devel

SRC_DIR=/opt/src/ffmpeg-php
[[ -d $SRC_DIR ]] || mkdir -p $SRC_DIR
cd $SRC_DIR
git clone https://github.com/tony2001/ffmpeg-php.git
cd ffmpeg-git
grep -ir avcodec_alloc_frame "$SRC_DIR" -l | xargs -I{} sed 's/avcodec_alloc_frame/av_frame_alloc/' -i {}
./configure
2016/01/29 21:43 · kyxap

Shell-wrapper для standalone passenger

/opt/scripts/passenger.sh
#!/usr/bin/env bash
 
_dir=/home/bundle     # app root dir
_home=/home/passenger # user home dir
_addr="0.0.0.0"
_port="8191"
 
_pid="$_home/passenger.pid"
_log="$_home/passenger.log"
_ngxtpl="$_home/nginx.conf.erb"
 
_args="--address $_addr --port $_port --user passenger --environment production --pid-file $_pid --log-file $_log --nginx-config-template $_ngxtpl --daemonize --sticky-sessions --app-type node --startup-file main.js"
 
[[ -f $_home/.nvm/nvm.sh ]] && source $_home/.nvm/nvm.sh
 
export MONGO_URL='mongodb://localhost:27017/mongodb'
export ROOT_URL="http://pro-manage.net:$_port"
 
[[ `whoami 2>/dev/null` == passenger ]] || echo "Run as passenger user"
 
cd $_dir
 
case $@ in
  stop)
    passenger stop --port $_port --pid-file $_pid
    ;;
  start)
    passenger start $_args
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  status)
    passenger status --port $_port --pid-file $_pid
    ;;
  *)
    echo "usage: $0 stop | start | restart | status"
    ;;
esac
2015/04/09 10:16 · kyxap

Быстрое удаление большого количества файлов

generate files

for i in $(seq 1 1000000); do echo testing >> $i.txt; done

rm

time rm -f *
-bash: /bin/rm: Argument list too long
real    0m11.126s
user    0m9.673s
sys     0m1.278s

find with -exec rm

time find ./ -type f -exec rm {} \;
real    14m51.735s
user    2m24.330s
sys     9m48.743s

find with -delete

time find ./ -type f -delete
real    5m11.937s
user    0m1.259s
sys     0m28.441s

perl

time perl -e 'for(<*>){((stat)[9]<(unlink))}'
real    1m0.488s
user    0m7.023s
sys     0m27.403s

rsync - empty test dir

rsync -a --delete /home/blanktest/ /home/test/
real    2m52.502s
user    0m2.772s
sys     0m32.649s
2015/02/25 21:59 · kyxap

Ключи для запуска clamav

clamscan -ri --detect-pua=yes --scan-mail=yes --phishing-sigs=yes --phishing-scan-urls=yes --heuristic-scan-precedence=yes --algorithmic-detection=yes --scan-pe=yes --scan-elf=yes --scan-ole2=yes --scan-pdf=yes --scan-html=yes --scan-archive=yes --detect-broken=yes --block-encrypted=yes /path/to/dir
2015/02/24 14:18 · kyxap

Использование GRE-туннеля в качестве транспорта для OpenVPN

Задача состояла в разделении точки входа и точки выхода для openvpn.

Entry node Exit node
OS Linux CentOS 6.x FreeBSD 9.x
Service openvpn server none
External IP 88.32.99.91 162.210.201.13
Internal IP 10.254.10.1 10.254.20.1
OpenVPN network 10.254.0.0/16
2015/01/22 07:36 · kyxap

Использование RAM-диска в качестве tmpdir для MySQL

[mysqld]
tmpdir=/tmp/mysql

[mysqldump]
tmpdir=/tmp

[client]
tmpdir=/tmp
2014/12/07 19:36 · kyxap

Простейший скрипт бекапа MySQL

#!/usr/bin/env bash
#
# Daily backup mysql databases
# CLI args: none

#exit on error
set -e

LANG=C
PATH="/bin:/usr/sbin:/usr/bin:/sbin:/usr/local/bin:/usr/local/sbin"

DATE=$(date +%F)
BACKUP_DIR=/home/mysql_backups
DUMP_DIR=$BACKUP_DIR/dumps
LOG=$BACKUP_DIR/backup.log

DAYS=7
DB="all"
OPTS="--order-by-primary --add-drop-database"

#########################

print_error() { echo "$@"; write_log "[ERROR] $@"; exit 1; }
print_info()  { echo "$@"; write_log "[INFO] $@"; }
write_log()   { echo "`date -R -u` $@" >> $LOG; }

##########################

# check dir
[[ -d $DUMP_DIR ]] || mkdir -p $DUMP_DIR

# check permissions on backup dir
if PERMS=$(stat --format="%a" $BACKUP_DIR)
then
  # restore chmod
  [[ $PERMS -eq 700 ]] || chmod 700 $BACKUP_DIR
fi

# check binaries
[[ -f `which mysqldump 2>/dev/null` ]] && MYSQLDUMP=mysqldump || print_error "No mysqldump binary found in $PATH"
[[ -f `which mysql 2>/dev/null` ]] && MYSQL=mysql || print_error "No mysql binary found in $PATH"

# validate $DB and skip default dbs
[[ $DB == all ]] && DB=$(mysql -e 'show databases' | tail -n +2 | grep -v -E "^(information_schema|performance_schema)$")

# create dumps
for db in $DB
do
  # is db exist?
  if ! EXISTS=$($MYSQL -s -N -e "show databases" | tail -n +2 | grep -x $db)
  then
    print_info "No such database: $db"
    break
  fi

  DUMP_FILE=$DUMP_DIR/$DATE/$db.sql.gz
  # is dump exist?
  [[ -s $DUMP_FILE ]] || (
    # log
    print_info "Creating new: $DUMP_FILE"

    # mkdir
    mkdir -p $DUMP_DIR/$DATE

    # add --events to mysql db
    [[ $db == mysql ]] && OPTS+=" --events"

    # dump
    $MYSQLDUMP $OPTS $db | gzip -1 > $DUMP_FILE
  )
done

# remove dirs
if OUTDATED_DIRS=$(find $DUMP_DIR -maxdepth 1 -type d -mtime +$DAYS)
then
  for dir in $OUTDATED_DIRS
  do
    # log
    print_info "Deleting outdated: $dir"

    # rm
    [[ -d $dir ]] && rm -r "$dir" || print_error "Can't remove $dir"
  done
fi

2014/09/01 20:40 · kyxap

Преобразование строк/таблиц/колонок

#!/usr/bin/env bash

export LANG=C # must have

# 1-column to tabs-separated multicolumn
cat 1-col.txt | sort | column

# 1-column to spaces-separated multicolumn
cat 1-col.txt | sort | column | expand

# 1-column to string w/delimiter
cat 1-col.txt | sort | paste -sd:

# multicolumn to 1-column
cat multi-col-spaces.txt | xargs -n 1 | sort

# string w/delimiter to 1-column
cat 1-string-delim.txt | tr ':' '\n' | sort
2014/05/18 04:23 · kyxap

Docker

2014/05/17 18:46 · kyxap

Скрипт добавления клиентского сертификата для OpenVPN

#!/usr/bin/env bash

# Usage: $0 with no args

set -e

PATH="/sbin:/bin:/usr/sbin:/usr/bin:/sbin:$PATH"
MAIL_TO='[email protected]'
SCRIPTS_DIR=/etc/openvpn/easy-rsa
ACCOUNTS_DIR=/etc/openvpn/KEYS

#####################################

function error_print
{
  echo "ERROR $1" 1>&2
  exit 1;
}

# read account
[[ -z $account ]] && echo -n "Provide account name to add: " || error_print "No account provided"
read account
[[ -z $account ]] && error_print "No account provided"

# cd scripts dir
[[ -d $SCRIPTS_DIR ]] && cd $SCRIPTS_DIR || error_print "No such dir $SCRIPTS_DIR"

# read vars
[[ -f vars ]] && source vars || error_print "No such file vars"

echo "Creating cert and key for $account"

# build key
[[ -x pkitool ]] && ./pkitool $account || error_print "No such file pkitool"

# make account dir
mkdir -p /etc/openvpn/KEYS/$account

# copy account cert & key
cp $SCRIPTS_DIR/keys/${account}.crt $SCRIPTS_DIR/keys/${account}.key $ACCOUNTS_DIR/$account/

# copy ca cert and tls key
cp $SCRIPTS_DIR/keys/ca.crt $SCRIPTS_DIR/keys/ta.key $ACCOUNTS_DIR/$account/

# generate ovpn config
cat > $ACCOUNTS_DIR/$account/${account}.ovpn << EOF
client
remote SERVER'S.EXTERNAL.IP
port 1194
proto tcp
dev tun
nobind
persist-key
persist-tun
ca ca.crt
cert ${account}.crt
key ${account}.key
tls-auth ta.key 1
cipher BF-CBC
#log-append /var/log/ovpn_$account.log
EOF

# remove old archive if exists
[[ -f $ACCOUNTS_DIR/${account}.zip ]] && rm -f $ACCOUNTS_DIR/${account}.zip

cd $ACCOUNTS_DIR

# creating archive
[[ -f `which zip 2>/dev/null` ]] && zip ${account}.zip -r $account

# sending email
[[ -f `which uuencode 2>/dev/null` ]] && uuencode ${account}.zip ${account}.zip | sendmail $MAIL_TO
2013/12/19 22:43 · kyxap

Включение vnc в Intel AMT через wsmancli на платформе Intel NUC D53427RKE

Предполагается что AMT изначально активирован через UEFI (CTRL+P при загрузке, все доступные опции в ENABLE), а так же в web-интерфейсе (https, port 16692) используется выделенный IP.
Единственный NIC обслуживает как плату AMT, так и сеть хоста. При этом вы НИКАК не можете получить доступ из хостовой системы к AMT: одно из многочисленных проявлений security модели Intel, которое невозможно обойти.
Включение VNC производится только со стороннего компьютера, через WS-Management API. Для работы с ним я использовал клиент wsmancli, который присутствует в репозитории Ubuntu, но отсутствует в Debian.
К сожалению, по прошествии полугода уже не могу вспомнить ключи, передаваемые MEI CLI для активации http-интерфейса, но могу сказать точно: предоставляемая Intel версия CLI не работает с ядрами от Debian Squeeze/Wheezy, а качество исходников требует множества правок, экспериментов с версиями gcc и веселых упражнений с флагами компилятора. В целом, активация VNC оказалась несколько нетривиальной задачей, т.к. на поддержку управления новыми версиями контроллера в Linux товарищи из Intel забили где-то в районе 2008-2009 года.

Для Debian Wheezy можно использовать следующий ubuntu-пакет и его зависимости:

Методом вдумчивого изучения документации к SDK AMT, был изготовлен следующий скрипт.
Основным затыком в процессе настройки стал пароль, который визуально соответствовал требованиям безопасности Intel и принимался API без ошибки - но настройки попросту не менялись.

It must be a strong password – exactly eight characters long, containing a capital letter, a lower case letter, a digit, and at least one 7-bit ASCII non alpha-numeric character above 32, (e.g. '!', '$', ';'). Note that “_” is considered alphanumeric. The password cannot contain the characters '"', ',', and ':'.

С описанием использованных параметров можно ознакомиться тут.

#!/usr/bin/env bash

CIM=http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2
AMT=http://intel.com/wbem/wscim/1/amt-schema/1
IPS=http://intel.com/wbem/wscim/1/ips-schema/1

# configure parameter
HOST=192.168.111.100
# admin password, defined through initial UEFI setup 
ADMIN_PW=yiexoob8Miup$
# password to access VNC remotely
VNC_PW=VaeZ1reu4aizi$

auth="-h $HOST -P 16992 -u admin -p $ADMIN_PW"

wsman put $IPS/IPS_KVMRedirectionSettingData $auth -k "SessionTimeout=10" -k "OptInPolicy=false" -k "RFBPassword=$VNC_PW" -k "Is5900PortEnabled=true" -k "RequestedState=2"

# DEBUG: track changes
#wsman get $IPS/IPS_KVMRedirectionSettingData $auth

2013/11/29 22:55 · kyxap

Копирование больших объемов данных в несколько потоков с помощью lftp

Примеры копирования при использовании авторизации по ssh-ключам.
Закрывающий слеш в пути к исходной директории обязателен.
Задание представляет из себя текстовый файл.

  • Выполнение задания
    lftp -f tasks.lftp
2013/11/09 22:19 · kyxap

Сборка пакета из исходников c помощью rpmbuild на примере Monit 5.6 под Centos 6.4

  1. Добавить юзера builder
  2. Установить yum install -y rpmdevtools pam-devel
  3. Зайти к builder в ~/
  4. Стянуть сюда же устаревший rpm с исходниками http://pkgs.repoforge.org/monit/monit-5.5-1.rf.src.rpm
  5. Проставить зависимости от SRPM: yum-builddep monit-5.5-1.rf.src.rpm
  6. Понизить привилегии до su - builder и войти в его $HOME. Все дальнейшие действия выполняются под пользователем.
  7. Создать build-окружение, запустив rpmdev-setuptree
  8. Установить пакет rpm -i monit-5.5-1.rf.src.rpm
  9. Изменить ~/rpmbuild/SPECS/monit.spec, в нем указываем Version: 5.6 и добавляем BuildRequires: pam-devel
  10. Стянуть в ~/rpmbuild/SOURCES обновленные исходники http://mmonit.com/monit/dist/monit-5.6.tar.gz
  11. Зайти в ~/rpmbuild/SPECS
  12. Скомпилировать обновленные до 5.6 пакеты: rpmbuild -ba monit.spec.
2013/11/07 07:59 · kyxap

Цветной вывод ls для FreeBSD

В пакете coreutils присутствуют GNU реализации ls и dircolors, что позволяет использовать привычные схемы подсветки.

# pkg install coreutils
alias grep="grep --color=auto"
[[ -x `which gdircolors` ]] && eval "$(gdircolors -b)" || export LSCOLORS=ExGxFxdxCxDxDxhbadExEx
[[ -x `which gls` ]] && alias ls="gls --color=auto" || alias ls="ls -G"
[[ -x `which gsed` ]] && alias sed="gsed"
2013/10/29 15:27 · kyxap

Преобразование CSV-форматированного текста в ASCII-таблицу (для VIM и stdout)

Подразумевается что в env уже есть

export PATH=~/bin/:$PATH
  1. Создаем ~/bin/tab
    • разрешаем выполнение
      chmod +x ~/bin/tab
    • ставим симлинку
      ln -s ~/bin/tab ~/bin/untab
  2. Форматируем данные, которые должны быть преобразованы в таблицу:
    • значения, разделенные запятыми
      1,my table,another field
      2,my table,yet another field
    • вызов tab -t сформирует заголовок из первой строки
      ID,Name,Description
      1,my table,another field
      2,my table,yet another field
  3. Выделяем блок данных в VISUAL MODE и выполняем:
    • для создания таблицы
      :'<,'>!tab
    • для удаления таблицы
      :'<,'>!untab
  4. Получаем
    ------------------------------------
    | 1 | my table | another field     |
    | 2 | my table | yet another field |
    ------------------------------------
  5. Такой же эффект получим при перенаправлении stdout:
    cat csv-formatted.txt | tab
    

Лучи добра засылать сюда.

tab
#!/usr/bin/env perl 
#===============================================================================
#
#         FILE:  tab
#
#        USAGE:  "tab" or "untab"
#
#  DESCRIPTION:  This will turn comma seperated input from stdin into a text table.  
#                It can also then convert it back if program is invoked as "untab".
#
#                As well as being used on the command line, tab/untab can be
#                used from within vi, and can work on tables that are commented
#                out with # or //.
#
#      OPTIONS: 
#                -------------------------------------------------------------------------
#                | Command/Option | Purpose                                              | 
#                |----------------|------------------------------------------------------|
#                | tab            | Reads from stdin and tabulates comma seperated input | 
#                | tab <-t>       | Tabulates input and assumes first row are titles     | 
#                | tab <-h>       | Prints this help                                     | 
#                | tab <-nb>      | Tabulates without a border                           | 
#                | tab <-fw X>    | Wrap fields greater than X big don't break words     | 
#                | tab <-fs X>    | Wrap fields greater than X big and break words       | 
#                | tab <-vp X>    | Vertically pad table by X lines                      | 
#                | tab <-hp X>    | Horizontally pad fields by X chars                   | 
#                | tab <-b X>     | Tabulates with a border made from char X             | 
#                |----------------|------------------------------------------------------|
#                | untab          | Reads from stdin and untabulates table input         | 
#                | untab <-b X>   | Untabulate a table with border char X                | 
#                | untab <-nb>    | Untabulate a borderless table                        | 
#                -------------------------------------------------------------------------
#
# REQUIREMENTS:  ---
#         BUGS:  ---
#        NOTES:  ---
#       AUTHOR:  Ben Staniford (BTS), <ben.staniford@g nospam mai l.com>
#      COMPANY:  
#      VERSION:  1.0
#      CREATED:  23/08/07 11:53:19 BST
#     REVISION:  ---
#===============================================================================
 
# TODO
# 1. Make tab and untab keep existing indentation including inside comments
# 2. Store the comment regexp only once in a global variable
# 3. Allow facility to set the delimiter on the command line
 
use strict;
use warnings;
 
#Default values (Normally set from cmd line)
my $HPADDING=1;                    #How much horizontal padding
my $VPADDING=0;                    #How much vertical padding
my $VBORDER="|";                   #What is our vertical border?
my $HBORDER="-";                   #What is our horizontal border/divider?
my $wrapped_line_vpad=1;           #Should we vertically pad fields that have been word wrapped?
my $break_words_on_wrap=1;         #Should we break words when wrapping
my $field_wrap_boundary=0;         #How big should a field be before we wrap it?
 
#Globals
my @max_field_sizes=();
my $max_col_count=0;
my $comment_char="";
my $titles=0;
 
#Funcs
sub tabulate();
sub get_fields($);
sub print_header_footer();
sub add_padding($);
sub	untabulate();
sub add_field_empty_space($$);
sub print_usage();
sub wrap_oversized_fields(@);
sub print_table_divider($);
 
#No STDERR under any circumstances
open (STDERR, ">/dev/null");
 
#Arguments
my $args = join ' ', @ARGV;
if ($args =~ /-t/) 			{ $titles=1; }
if ($args =~ /-nb/) 		{ $VBORDER=""; $HBORDER=""; $HPADDING=2;}
if ($args =~ /-b\s+(\S)/)  	{ $VBORDER=$1; $HBORDER=$1; $HPADDING=1;}
if ($args =~ /-fs\s+(\S+)/) { $field_wrap_boundary=$1; $break_words_on_wrap=0;}
if ($args =~ /-fw\s+(\S+)/) { $field_wrap_boundary=$1; $break_words_on_wrap=1;}
if ($args =~ /-vp\s+(\S+)/) { $VPADDING=$1}
if ($args =~ /-hp\s+(\S+)/) { $HPADDING=$1}
elsif ($args =~ /-h/) 		{ print_usage(); exit 0; }
 
#If we're invoked as "untab", i.e. via symlink, do the inverse of normal behavior
#Note, untab uses most of the same program arguments above.
chomp(my $PROGRAM_NAME = `basename $0`);
if ($PROGRAM_NAME eq "untab") {
	untabulate();
} else {
	tabulate();
}
exit 0;
 
# ------------------------------------------------------------------
# | Name         | Purpose                            | Parameters | 
# |--------------|------------------------------------|------------|
# | tabulate()   | Main function that tabulates stdin |            | 
# ------------------------------------------------------------------
sub tabulate() {
 
	#Step 1, load the data into a list
	my @table=<STDIN>;
 
	#Step 2, If we have field length restrictions, reorder the table as
	#needed.  Note, this can't be untabbed.
	if ($field_wrap_boundary != 0) {
		@table = wrap_oversized_fields(@table);
	}
 
	#Step 3, calculate the number of rows and columns from the input as well as the 
	#maximum field size for each column.  Also, work out if this table is in a comment.
	for my $line (@table) {
		chomp $line;
		my @fields = get_fields($line);
		my $counter=0;
 
		#Work out if the data is inside a comment
		if ($counter==0 && $line=~/^(\#|\/\/)/) {
			$comment_char=$1;
		}
 
		$line =~ s/^$comment_char//;
 
		for my $field (@fields) {
			if (!defined $max_field_sizes[$counter]) {
				$max_field_sizes[$counter] = 0;
			}
			if ($max_field_sizes[$counter] < length($field)) {
				$max_field_sizes[$counter] = length($field);
			}
			$counter++;
		}
 
		if ($counter > $max_col_count) {
			$max_col_count=$counter;
		}
	}
 
	#Step 4, print out the table
	print_header_footer();
	my $lcounter=0;
	for my $line (@table) {
		chomp $line;
		my @fields = get_fields($line);
 
		if ($comment_char ne "") {
			print "$comment_char ";
		}
 
		if ($VBORDER ne "") {
			print $VBORDER.add_padding(" ");
		}
		$lcounter++;
 
		my $counter=0;
		#Print fields
		for my $field (@fields) {
			print "$field".add_field_empty_space(length($field), $counter).add_padding(" ");
			print $VBORDER.add_padding(" ");
			$counter++;
		}
		#Print any empty fields (if they exist)
		if ($counter < $max_col_count) {
			for (my $i=0;$i<($max_col_count - $counter);$i++) {
				print add_field_empty_space(0, $counter+$i).add_padding(" "); 
				print $VBORDER.add_padding(" ");
			}
		}
		print "\n";
		if ($VPADDING==1) {
			print_table_divider(" ");
		}
		if ($titles && $lcounter==1) {
			#print_header_footer();
			print_table_divider($HBORDER);
		}
	}
	print_header_footer();
}
 
# -----------------------------------------------------------------------------
# | Name                  | Purpose                | Parameters               | 
# |-----------------------|------------------------|--------------------------|
# | print_table_divider() | Print out a divider in | Character divider should | 
# |                       | the table              | made from                | 
# -----------------------------------------------------------------------------
sub print_table_divider($) {
 
	my $divider_char = shift;
 
	if ($divider_char eq $HBORDER && $HBORDER eq "") {
		return;
	}
	if ($comment_char ne "") {
		print "$comment_char ";
	}
	for my $size (@max_field_sizes) {
		print $VBORDER.add_padding($divider_char);
		for (my $i=0;$i<$size;$i++) {
			print $divider_char;
		}
		print "".add_padding($divider_char);
	}
	print $VBORDER."\n";
}
 
 
# ----------------------------------------------------------------------------
# | Name                   | Purpose                            | Parameters | 
# ----------------------------------------------------------------------------
# | print_header_footer()  | Print out the tables header/footer |            | 
# ----------------------------------------------------------------------------
sub print_header_footer() {
 
	my $divider_char = $HBORDER;
 
	if ($divider_char eq $HBORDER && $HBORDER eq "") {
		return;
	}
	if ($comment_char ne "") {
		print "$comment_char ";
	}
	for my $size (@max_field_sizes) {
		print $HBORDER.add_padding($divider_char);
		for (my $i=0;$i<$size;$i++) {
			print $divider_char;
		}
		print "".add_padding($divider_char);
	}
	print $HBORDER."\n";
 
}
 
# ------------------------------------------------------------------------------
# | Name                     | Purpose                    | Parameters         | 
# ------------------------------------------------------------------------------
# | add_field_empty_space()  | Print out the field spacer | Field Length (int) | 
# |                          |                            | Field Number (int) | 
# ------------------------------------------------------------------------------
sub add_field_empty_space($$) {
	my $ret="";
	my $field_length=shift;
	my $field_number=shift;
	my $empty_space_size=$max_field_sizes[$field_number] - $field_length;
	for (my $i=0;$i<$empty_space_size;$i++) {
		$ret.=" ";
	}
	return $ret;
}
 
# -----------------------------------------------------------------------------
# | Name          | Purpose                      | Parameters                 | 
# |---------------|------------------------------|----------------------------|
# | add_padding   | Print out the padding string | Padding character (string) | 
# -----------------------------------------------------------------------------
sub add_padding($) {
	my $padding_char = shift;
	my $ret="";
	for (my $i=0;$i<$HPADDING;$i++) {
		$ret.=$padding_char;
	}
	return $ret;
}
 
# -----------------------------------------------------------------------------
# | Name         | Purpose                              | Parameters          | 
# |--------------|--------------------------------------|---------------------|
# | get_fields   | Extract a list of fields from a line | Input line (string) | 
# -----------------------------------------------------------------------------
sub get_fields($) {
	my $line=shift;
	my @fields = split ',',$line;
	my @ret=();
	for my $field (@fields) {
		$field =~ s/^\s*//;
		$field =~ s/\s*$//;
		push @ret, $field;
	}
	return @ret;
}
 
# -----------------------------------------------------------------------------------
# | Name           | Purpose                                           | Parameters | 
# |----------------|---------------------------------------------------|------------|
# | untabulate()   | Perform the inverse function and untabulate stdin |            | 
# -----------------------------------------------------------------------------------
sub untabulate() {
 
	my $counter=0;
	while (<STDIN>) {
 
		chomp;
 
		#Work out if the data is inside a comment
		if ($counter==0 && $_=~/^(\#|\/\/)/) {
			$comment_char=$1;
		}
 
		#Handle a borderless table specifically
		if ($HBORDER eq "" && $VBORDER eq "") {
			s/\s{2,200}/,/g;
			s/,$//;
		#This is a table with a border
		} else {
			my $hb_regexp="\\$HBORDER";
			my $vb_regexp="\\$VBORDER";
			s/^$hb_regexp*$//g;
			s/^(?:$hb_regexp|$vb_regexp)*$//;
			s/^$comment_char\s*$hb_regexp*$//g;
			s/\s*$vb_regexp\s*/,/g;
		}
 
		s/^$comment_char\,/$comment_char/;
		for (my $i=0;$i<20;$i++) {
			s/^\,//;
			s/\,$//;
		}
 
		s/,/, /g;   #If you want spaces as the default after commas
		if ($_ !~ /$comment_char\s/) {
			s/$comment_char/$comment_char /;
		}
		if ($_ !~ /^\s*$/) {
			print "$_\n";
		}
		$counter++;
	}
 
}
 
# ----------------------------------------------------------------------------------------
# | Name                      | Purpose                                  | Parameters    | 
# |---------------------------|------------------------------------------|---------------|
# | wrap_oversized_fields()   | Wrap fields that are more than specified | List of lines | 
# |                           | size.  This works by rewriting the       |               | 
# |                           | comma seperated data so that extra lines |               | 
# |                           | are made.  For this reason this          |               | 
# |                           | function cannot easily be undone by "    |               | 
# |                           | untab"                                   |               | 
# ----------------------------------------------------------------------------------------
sub wrap_oversized_fields(@) {
 
	my @table=@_;
	my @ret;
 
	#Go through each line in the table
	for my $line (@table) {
		my @overflow_buffer=();
		chomp $line;
		my $lcounter=0;
 
		#Work out if the data is inside a comment
		if ($lcounter==0 && $line=~/^(\#|\/\/)/) {
			$comment_char=$1;
		}
 
		$line =~ s/^$comment_char//;
 
		my @fields = get_fields($line);
		my @overflow_fields = ();
		my $fcounter = 0;
 
		#Go through fields in each line looking for fields that must be split
		for my $field (@fields) {
			if (length($field) > $field_wrap_boundary) {
				my $temp;
				#Wrap and preserve words
				if ($break_words_on_wrap) {
					while ($field =~ /^(.{0,$field_wrap_boundary}\b)/) {
						$overflow_fields[$fcounter].=",$1";
						$field=$';
					}
				#Wrap and split words
				} else {
					while ($temp = substr($field, 0, $field_wrap_boundary)) {
						$temp =~ s/^\s*//;
						$overflow_fields[$fcounter].=",$temp";
						$field=substr($field, $field_wrap_boundary,length($field));
					}
				}
			} else {
				$overflow_fields[$fcounter]=$field;
			}
			$fcounter ++;
		}
 
		#Build the extra lines that must be put back into @table using the
		#@overflow_fields table
		$fcounter=0;
		my $keep_processing=1;
		while ($keep_processing) {
 
			$keep_processing=0;
 
			my $counter = 0;
			for (@overflow_fields) {
 
				my $field, my $remainder;
				if( ($field, $remainder) = /^,(.*?)(,.*)$/) {
					my $a=1;
				} else {
					$field=$_;
					$field=~s/^,//;
				}
				if ($field ne "") { $keep_processing = 1; }
 
				#Put any extra lines we make into the overflow buffer so that
				#that can be added into our return result.
				$overflow_buffer[$fcounter].=",$field";
				$overflow_fields[$counter]=$remainder;
				$counter++;
			}
			$fcounter++;
		}
 
		#Put the contents of the overflow buffer into our return result
		for $line (@overflow_buffer) {
			#print "OB: $line\n";
			$line =~ s/^,//;
			if ($line !~ /^,*$/) {
				push @ret, $line;
			} elsif ($wrapped_line_vpad==1) {
				push @ret, $line;
			}
		}
 
		$lcounter++;
	}
	return @ret;
 
}
 
sub print_usage() {
 
print <<END;
-------------------------------------------------------------------------
| Command/Option | Purpose                                              | 
|----------------|------------------------------------------------------|
| tab            | Reads from stdin and tabulates comma seperated input | 
| tab <-t>       | Tabulates input and assumes first row are titles     | 
| tab <-h>       | Prints this help                                     | 
| tab <-nb>      | Tabulates without a border                           | 
| tab <-fw X>    | Wrap fields greater than X big don't break words     | 
| tab <-fs X>    | Wrap fields greater than X big and break words       | 
| tab <-vp X>    | Vertically pad table by X lines                      | 
| tab <-hp X>    | Horizontally pad fields by X chars                   | 
| tab <-b X>     | Tabulates with a border made from char X             | 
|----------------|------------------------------------------------------|
| untab          | Reads from stdin and untabulates table input         | 
| untab <-b X>   | Untabulate a table with border char X                | 
| untab <-nb>    | Untabulate a borderless table                        | 
-------------------------------------------------------------------------
END
 
 
}
2013/10/18 04:56 · kyxap

Включение поддержки HTTPS для серверов с self-signed сертификатом после изменений в LWP 6

Добавить в .pl-скрипт:

$ENV{PERL_NET_HTTPS_SSL_SOCKET_CLASS} = "Net::SSL";
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;

$ENV{HTTPS_VERSION} = '3';
$ENV{HTTPS_DEBUG} = 0;

2013/09/25 16:21 · kyxap

Безопасное обновление ядра через ssh в Debian

Во избежание потенциальных проблем с удаленным обновлением ядра, я пользуюсь механизмом fallback, реализованном в grub уже довольно давно.
В данном случае используется grub2, принятый по умолчанию в Debian Wheezy.

Обязательные элементы конфига загрузчика:

GRUB_DEFAULT=saved
GRUB_CMDLINE_LINUX_DEFAULT="panic=30"

В случае kernel panic сервер будет автоматически возвращен в последнее стабильное ядро. Мой конфиг загрузчика:

# grep ^[^#] /etc/default/grub
GRUB_DEFAULT=saved
GRUB_TIMEOUT=15
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on panic=30"
GRUB_CMDLINE_LINUX=""
GRUB_DISABLE_OS_PROBER=true

Просматриваем доступные загрузчику ядра:

# grub-mkconfig 2>/dev/null | perl -ne 'print "$1\n" if m/^menuentry.+?'\''(.+?)'\''/'
Debian GNU/Linux, with Linux 3.11.0-031100rc5-generic
Debian GNU/Linux, with Linux 2.6.32-23-pve

Текущее ядро - стабильное, при проблемах мы вернемся именно в него:

# uname -rs
Linux 2.6.32-23-pve

Выставляем его в fallback:

# grub-set-default 'Debian GNU/Linux, with Linux 2.6.32-23-pve'

Ядро 3.11-rc5 является релиз-кандидатом, но в нем на данный момент наиболее полно реализована поддержка новых чипсетов под процессоры Haswell.
Команда grub-reboot разрешит загрузиться этому ядру только один раз. Реальной перезагрузки не произойдет.

# grub-reboot 'Debian GNU/Linux, with Linux 3.11.0-031100rc5-generic'

Инсталляции Debian, произведенные не через debian-installer, зачастую не содержат в себе post-hook на перегенерацию initrd.
Поэтому выполняем его вручную:

# update-initramfs -k all -u

Обновляем конфиг загрузчика:

# update-grub2

Перезагружаем сервер в новое ядро:

# reboot

В случае успешной загрузки нового ядра сообщаем grub'у что теперь будем использовать обновленную версию:

# grub-set-default 'Debian GNU/Linux, with Linux 3.11.0-031100rc5-generic'
2013/08/16 23:37 · kyxap

Установка групп пакетов в Debian Wheezy (minimal => standard)

Все просто.

apt-get install tasksel
aptitude install ~pstandard ~prequired ~pimportant -F%p
2013/08/06 10:56 · kyxap

Откат c testing до stable на примере Debian Wheezy 7.1

/etc/apt/apt.conf не должен содержать в себе упоминаний APT::Default-Release

/etc/apt/sources.list

deb http://mirror.yandex.ru/debian/ wheezy main contrib non-free
deb http://mirror.yandex.ru/debian/ jessie main contrib non-free  
deb http://security.debian.org/ jessie/updates main contrib non-free


Для отката с testing до stable достаточно внести в /etc/apt/preferences следующие записи:

Package: *
Pin: release a=stable
Pin-Priority: 1001

Package: *
Pin: release a=testing
Pin-Priority: 900

Package: *
Pin: release a=unstable
Pin-Priority: 800

Package: *
Pin: release o=Debian
Pin-Priority: -1

Если команда apt-cache policy выдает правильные приоритеты, то поочередно выполняем apt-get upgrade и apt-get dist-upgrade, после чего мы остаемся на ветке stable.
Теперь можем добавить в /etc/apt/apt.conf строку APT::Default-Release "wheezy";

2013/07/25 18:48 · kyxap
start.1474507226.txt.gz · Last modified: 2016/09/22 01:20 by kyxap