Создание релиза FreeBSD Андрей Елсуков # cvsup –g –L 2 /mnt/cvs/cvs-supfile *default host=cvsup2.FreeBSD.org *default base=/var/db *default prefix=/mnt/cvs/ncvs *default release=cvs *default delete use-rel-suffix *default compress src-all ports-all doc-all cvsroot-all # cd /usr/home # mkdir release # mount_nfs –o rdonly server:/usr/home/cvs /mnt # cvs –Rd /mnt/ncvs co –Pr RELENG_5 src # cd src/ # mv /etc/make.conf /etc/make.conf.old # make –j8 buildworld # cd release/ # vim start.sh make –j8 CHROOTDIR=/usr/home/release BUILDNAME=5.3-STABLE CVSROOT=/mnt/ncvs RELEASETAG=RELENG_5 DOC_LANG=”en_US.ISO8859-1 ru_RU.KOI8-R” NOPORTREADMES=yes RELEASENOUPDATE=yes release # mount_nfs –o rdonly server:/usr/ports/distfiles /usr/home/release/usr/ports/distfiles # vim start.sh #!/usr/local/bin/perl foreach(`ls All/`) { chop; s/\.t.z$//; `grep -E "^$_" ../INDEX-5 >> INDEX`; } # mkdir /usr/home/release/usr/ports/packages # cp mkindex.pl /usr/ports/packages # chroot /usr/home/release # cd /usr/ports/lang/perl5.8 && make package-recursive # cd /usr/ports/x11/xorg && make package-recursive # cd /usr/ports/x11/xorg-manpages && make package-recursive # cd /usr/ports/packages # ./mkindex.pl # rm mkindex.pl # cp –PRv /usr/ports/packages /R/cdrom/disc1/ # exit Конструктивный Dialog Сергей Супрунов Пример 1: apctl.sh – Сценарий управления сервером Apache #!/bin/sh # apctl.sh dialog --title "Apachectl interface" \ --menu " Данный сценарий управляет сервером Apache. Выберите действие из предложенных ниже:" 17 50 8 \ start "Запуск сервера Apache" \ stop "Останов сервера Apache" \ restart "'Жесткий' перезапуск" \ graceful "'Мягкий' перезапуск" \ status "Статус сервера" \ fullstatus "Подробный статус" \ configtest "Тест конфигурационного файла" \ help "Вывод справки" 2> apctl.tmp COMMAND=`cat apctl.tmp` COMMAND="/usr/local/sbin/apachectl $COMMAND" dialog --title "Apachectl interface" \ --yesno " ВНИМАНИЕ! Будет выполнена следующая команда: $COMMAND Продолжить?" 10 50 if [ $? = 0 ]; then $COMMAND fi rm apctl.tmp ErrorDocument 404 “Запрошенная страница не существует ErrorDocument 404 /_srv_/error404.html ErrorDocument 404 http://my.server.ru/errors/error404.htm AddHandler server-parsed .shtml .shtm Пример 2: mkhtac.sh – Сценарий для создания .htaccess #!/bin/sh # mkhtac.sh # Создание вспомогательных файлов TF=`mktemp –t dlg` TF_TREE=`mktemp –t tree` # Запись в файл дерева каталогов find www -type d > $TF_TREE # Регистрация обработчика сигналов trap "rm -f $TF $TF_TREE" 0 2 9 15 #==[Dialog 0]== dialog --title "Make .htaccess: Confirmation" \ --yesno " Данный сценарий поможет вам создать файл .htaccess. Продолжить?" 10 40 if [ $? != 0 ]; then exit fi #==[Dialog 1]== dialog --title "Make .htaccess: Select dir" \ --ftree $TF_TREE "/" " Укажите каталог, в котором должен быть создан файл .htaccess:" 19 40 10 2> $TF if [ $? != 0 ]; then exit fi HTDIR=`cat $TF` #==[Dialog 2]== dialog --title "Make .htaccess: Select options" \ --checklist " Укажите опции, которые следует добавить в формируемый .htaccess:" 15 50 2 \ ErrorDocument "Обработка ошибки 404" OFF \ AddHandler "Включение SSI" OFF 2> $TF if [ $? != 0 ]; then exit fi ERROR=`grep "ErrorDocument" $TF` SSI=`grep "AddHandler" $TF` if [ "$ERROR" != "" ]; then #==[Dialog 3a]== dialog --title "Make .htaccess: ErrorDocument" \ --radiolist " Выберите один из способов обработки ошибки 404:" 15 60 3 \ MSG "Текстовое сообщение об ошибке" ON \ FILE "Перенаправление на локальный файл" OFF \ REDIR "Перенаправление на удаленный ресурс" OFF 2> $TF ERR_MSG=`grep "MSG" $TF` ERR_FILE=`grep "FILE" $TF` ERR_REDIR=`grep "REDIR" $TF` QUOT="" if [ "$ERR_MSG" != "" ]; then QUOT="\"" TEXT=" Введите текст сообщения об ошибке 404:" fi if [ "$ERR_FILE" != "" ]; then TEXT=" Введите абсолютное имя файла (от корня веб-сервера) или имя относительно текущего каталога: Пример: /errors/err404.html" fi if [ "$ERR_REDIR" != "" ]; then TEXT=" Введите полный URL ресурса (включая наименование протокола): Пример: http://my.server.ru/errors/err404.html" fi #==[Dialog 3b]== dialog --title "Make .htaccess: ErrorDocument" \ --inputbox "$TEXT" 10 70 2> $TF ERRMSG=`cat $TF` ERR2HT="ErrorDocument 404 $QUOT$ERRMSG" echo $ERR2HT fi if [ "$SSI" != "" ]; then #==[Dialog 4a]== dialog --title "Make .htaccess: SSI parse" \ --checklist " Отметьте, какие файлы должны обрабатываться парсером SSI:" 15 40 4 \ ".shtml" "файлы shtml" ON \ ".shtm" "файлы shtm" ON \ ".html" "файлы html" OFF \ ".htm" "файлы htm" OFF 2> $TF EXTLST=`cat $TF | tr "\"" "\0"` SSI2HT="AddHandler server-parsed $EXTLST" echo $SSI2HT fi # Запись результатов в файл .htaccess HTFILE=$HTDIR/.htaccess touch $HTFILE [ "$ERR2HT" != "" ] && echo $ERR2HT >> $HTFILE [ "$SSI2HT" != "" ] && echo $SSI2HT >> $HTFILE #==========================[Dialog 5]== dialog --title "Make .htaccess: Finish" \ --msgbox " Работа завершена. Сейчас созданный файл будет выведен на экран, чтобы вы могли ознакомиться с результатом. Дальнейшие изменения в созданный файл можно будет выполнить вручную." 15 50 #==[Dialog 6]== dialog --title "Make .htaccess: Result" \ --textbox $HTFILE 15 50 $ dialog --create-rc Почтовый сервер на базе Postfix Защита от вирусов и нежелательной почты минимальными средствами Геннадий Дмитриев # groupadd filter –g 551 # mkdir /var/spool/filter /var/spool/filter/spamd # useradd -u 542 -g 551 -d /var/spool/filter/spamd -s /sbin/nologin avpclient # useradd -u 543 -g 551 -d /nonexistent -s /nonexistent avpdaemon # chown avpclient:filter /var/spool/filter/spamd # cd /var/spool/filter/avp # mkdir Bases ctl dev etc proc tmp tst usr var var/log # chown –R avpdaemon:filter Bases ctl tmp tst var # cd dev # mknod console c 0 0 # mknod null c 2 2 # tar xzvf kavwslinux-4.0.3.1.tgz # cd kavwslinux # ls –all AvpUnix.ini [AVP32] # Меняем путь к основному конфигурационному файлу DefaultProfile=defUnix.prf [Configuration] KeysPath=. # Прописываем путь к вирусным базам от корневого каталога BasePath=/Bases defUnix.prf # same section with parameters for objects [Object] # Указываем каталог, в котором будем проводить сканирование # файла на вирусы Names=*/tst # Отключаем сканирование памяти и секторов логических томов Memory=No Sectors=No # Указываем параметры сканирования упакованных файлов, # архивов, саморазворачивающихся архивов и так далее Packed=Yes Archives=Yes SelfExtArchives=Yes MailBases=Yes MailPlain=Yes Embedded=Yes # Устанавливаем реакцию на обнаружение вируса в теле письма # «3» означает удаление тела вируса без попыток его лечения InfectedAction=3 # Требуем не архивировать письмо в случае обнаружения вируса BackupInfected=No IfDisinfImpossible=1 [Report] # Требуем вести файл журнала Report=Yes UseSysLog=No # Прописываем путь к файлу журнала ReportFileName=/var/log/kavscan.log # Отключаем расширенные формы записи в журнале ExtReport=No RepForEachDisk=No LongStrings=Yes # Отключаем пользовательский файл журнала UserReport=No # Устанавливаем реакцию на обнаружение вируса: не делать # копии писем [ActionWithInfected] InfectedCopy=No # Устанавливаем порядок действий при подозрении на вирус: # не делать копии писем [ActionWithSuspicion] SuspiciousCopy=No # Устанавливаем порядок действий в случае, если не удалось # распаковать файл (считаем его поврежденным): не делать # копии писем [ActionWithCorrupted] CorruptedCopy=No [TempFiles] # Устанавливаем предельный размер сканируемых файлов # и определяем каталог для временных файлов UseMemoryFiles=Yes LimitForMemFiles=6000 MemFilesMaxSize=20000 TempPath=/tmp [Customize] # Отключаем проверку необходимости обновления вирусных баз. # Данная опция необходима для работы антивирусной программы # без вмешательства администратора. В противном случае # она будет просить обновить базы каждый раз при загрузке UpdateCheck=No # Отключаем все лишние предупреждения на консоли сервера OtherMessages=No RedundantMessage=No DeleteAllMessage=No updater.sh #!/bin/sh /var/spool/filter/avp/kavupdater -y -kb -ui=http://downloads2.kaspersky-labs.com/updates/ -b=/var/spool/filter/avp/Bases /etc/init.d/kavd restart /etc/init.d/kavd # Указываем каталог, в который установлен антивирусный фильтр INSTPATH=/var/spool/filter/avp # Указываем каталог, в котором будем тестировать файлы AVPDIR="/tst" # Указываем каталог для хранения сокета AVPPIPE="/ctl" # Указываем параметры запуска демона DPARMS="-Y -MP -f=$AVPPIPE -dl -MD -I0 -o{$AVPDIR} $AVPDIR" # Строки, проверяющие наличие конфигурационных и ключевых # файлов, можно исключить. В случае корректной настройки # системы они не нужны. Далее в секции запуска демона # убираем проверку демонстрационной версии, наличия вирусных # баз и корректируем строку запуска самого демона. Почему # она выглядит именно так, будет объяснено чуть позже start () { if [ -r "$PIDFILE" ]; then echo "$NAME is running" exit 1 fi cd $INSTPATH echo -n "Starting $DESC: " daemon "/bin/env - HOME=/ /bin/nice/ var/spool/filter/avp/uchroot -u avpdaemon $INSTPATH /kavdaemon $DPARMS" RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$NAME cd $WD } daemon "/bin/env - HOME=/ /bin/nice /var/spool/filter/avp/uchroot -u avpdaemon $INSTPATH /kavdaemon $DPARMS" # cd /home/gennadiy # tar xzvf avcheck-0.8.tar.gz # cd avcheck-0.8 # make # cp avcheck /var/spool/filter/avp/ # cp uchroot /var/spool/filter/avp/ # mkdir /var/spool/filter/avp/infected # cp infected.ex2.ru /var/spool/filter/avp/infected infected.ex2.ru # Оставляем данную строчку пустой, чтобы не посылать лишних # сообщений отправителю и получателю вирусного сообщения VIRUS_ALERT= # Отключаем информативные сообщения отправителю и получателю INFORM_SENDER=n # no send alert INFORM_RCPT=n # send alert to recipients # Удаляем функции attach_message() и attach_message_headers() # В секции генерации предупреждения администратору убираем # вызов функции attach_message(). Также в случае, если мы # не используем информативные сообщения отправителю # и получателю вирусного письма, можно удалить секции # «send alert to sender» # «alert to recipients» # tar xzvf Mail-SpamAssassin-3.0.2.tar.gz # cd Mail-SpamAssassin-3.0.2 # make # make install local.cf # don't use agent use_razor2 0 use_dcc 0 use_pyzor 0 # check rbl skip_rbl_checks 0 # autowhitelist use_auto_whitelist 1 auto_whitelist_path /var/spool/filter/spamd/auto_whitelist # bayes use_bayes 1 bayes_auto_learn 0 bayes_path /var/spool/filter/spamd/bayes bayes_expiry_max_db_size 1500000 bayes_auto_learn_threshold_nonspam 0.1 bayes_auto_learn_threshold_spam 10.0 bayes_min_ham_num 100 bayes_min_spam_num 200 auto_learn 0 ok_languages en ru ok_locales en ru # Spam header rewriting – clear_headers rewrite_header subject ****SPAM (_SCORE_)**** required_hits 3.5 # user rules allow_user_rules 0 # report options always_add_report 1 report_safe 0 report_charset koi8-r # dns testing dns_available no # score options score FROM_ILLEGAL_CHARS 1.5 score HEAD_ILLEGAL_CHARS 1.5 score SUBJ_ILLEGAL_CHARS 1.5 score SUBJ_HAS_SPACES 2.5 score NO_REAL_NAME 1.0 score PENIS_ENLARGE 3.5 score PENIS_ENLARGE2 3.5 score FROM_HAS_MIXED_NUMS 1.0 score FORGED_IMS_TAGS 0.5 score FORGED_MUA_OUTLOOK 0.5 score FORGED_OUTLOOK_TAGS 0.5 score BAYES_80 3.5 score BAYES_90 4.0 score BAYES_99 10.0 # network whitelist whitelist_from localhost /etc/init.d/spamd # Set default spamd configuration. SPAMDOPTIONS="-d -m 5 -u avpclient -x -r /var/run/spamd/spamd.pid" main.cf content_filter=avcheck master.cf # check mail with spamd and kaspersky avcheck unix - n n - 5 pipe flags=q user=avpclient argv=/usr/bin/spamc -u avpclient -e /var/spool/filter/avp/avcheck -i /var/spool/filter/avp/infected/infected.ex2.ru -h Ok -d /var/spool/filter/avp/./tst -s AVP:/var/spool/filter/avp/ctl/AvpCtl -f ${sender} -S :1025 -- ${recipient} localhost:1025 inet n - n - - smtpd -o content_filter= # rpm –Uvh postfix-2.1.5-4.rhel3.i386.rpm main.cf header_checks=regexp:/etc/postfix/header.regexp header.regexp /^X-Spam-Flag: YES/ REDIRECT spam@company.ru Режем спам Дополнительные методы Денис Назаров /etc/rc.conf spamd_flags="" # for normal use: "" and see spamd-setup(8) spamd_grey=YES # use spamd greylisting if YES Crontab 0 * * * * /usr/libexec/spamd-setup /etc/spamd.conf all:\ :spamhaus:spews1:spews2:china:korea:whitelist:blacklist: # Mirrored from # http://spfilter.openrbl.org/data/sbl/SBL.cidr.bz2 spamhaus:\ :black:\ :msg="SPAM. Your address %A is in the Spamhaus Block List\n\ See http://www.spamhaus.org/sbl and\ http://www.abuse.net/sbl.phtml?IP=%A for more details":\ :method=http:\ :file=www.openbsd.org/spamd/SBL.cidr.gz # Mirrored from http://www.spews.org/spews_list_level1.txt spews1:\ :black:\ :msg="SPAM. Your address %A is in the spews level 1 database\n\ See http://www.spews.org/ask.cgi?x=%A for more details":\ :method=http:\ :file=www.openbsd.org/spamd/spews_list_level1.txt.gz # Mirrored from http://www.spews.org/spews_list_level2.txt spews2:\ :black:\ :msg="SPAM. Your address %A is in the spews level 2 database\n\ See http://www.spews.org/ask.cgi?x=%A for more details":\ :method=http:\ :file=www.openbsd.org/spamd/spews_list_level2.txt.gz # Mirrored from http://www.okean.com/chinacidr.txt china:\ :black:\ :msg="SPAM. Your address %A appears to be from China\n\ See http://www.okean.com/asianspamblocks.html for more details":\ :method=http:\ :file=www.openbsd.org/spamd/chinacidr.txt.gz # Mirrored from http://www.okean.com/koreacidr.txt korea:\ :black:\ :msg="SPAM. Your address %A appears to be from Korea\n\ See http://www.okean.com/asianspamblocks.html for more details":\ :method=http:\ :file=www.openbsd.org/spamd/koreacidr.txt.gz # Whitelists are done like this, and must be added # to «all» after each blacklist from which you want # the addresses in the whitelist removed whitelist:\ :white:\ :file=/var/mail/whitelist.txt blacklist:\ :black:\ :msg="SPAM! Go fsck anyone else!":\ :file=/var/mail/blacklist.txt relaydb-black:\ :black:\ :msg="SPAM. Your address %A is in my relaydb list.":\ :method=exec:\ :file=relaydb -4lb: relaydb-white:\ :white:\ :method=exec:\ :file=relaydb -4lw: blacklist:\ :black:\ :msg="SPAM! Go fsck anyone else!":\ :file=/var/mail/blacklist.txt # cat /var/mail/blacklist.txt # cat /var/mail/whitelist.txt all:\ :spamhaus:spews1:spews2:china:korea:whitelist:blacklist: /etc/pf.conf table persist table persist rdr pass inet proto tcp from to any port smtp -> 127.0.0.1 port 8025 rdr pass inet proto tcp from ! to any port smtp -> 127.0.0.1 port 8025 # ps ax | grep -i spa /etc/postfix/main.cf # # Our stuff for coniguring Postfix goes here # disable_vrfy_command = yes smtpd_helo_required = yes smtpd_helo_restictions = permit_mynetworks, reject_invalid_hostname, reject_unknown_hostname, reject_non_fqdn_hostname smtpd_sender_restrictions = reject_unknown_sender_domain, check_sender_access hash:/etc/postfix/reject # postmap /etc/postfix/reject smtpd_recipient_restrictions = reject_invalid_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_unauth_pipelining, permit_mynetworks, reject_unauth_destination, reject_rbl_client relays.visi.com, reject_rbl_client relays.ordb.org, reject_rbl_client list.dsbl.org, reject_rbl_client dnsbl.sorbs.net, reject_rbl_client dnsbl.void.ru, reject_rbl_client blackholes.mail-abuse.org, reject_rbl_client relays.mail-abuse.org, reject_rbl_client dul.mail-abuse.org, reject_rbl_client relays.ordb.org, reject_rbl_client blackholes.wirehub.net, reject_rbl_client dynablock.wirehub.net, reject_rbl_client dnsbl.njabl.org, reject_rbl_client list.dsbl.org, reject_rbl_client opm.blitzed.org, reject_rbl_client http.dnsbl.sorbs.net, reject_rbl_client socks.dnsbl.sorbs.net, reject_rbl_client misc.dnsbl.sorbs.net, reject_rbl_client smtp.dnsbl.sorbs.net, reject_rbl_client web.dnsbl.sorbs.net, reject_rbl_client bl.spamcop.net, reject_rbl_client dev.null.dk, reject_rbl_client blackholes.mail-abuse.com, reject_rbl_client relays.mail-abuse.com, reject_rbl_client dialups.mail-abuse.com, reject_rbl_client relays.ordb.org, reject_rbl_client list.dsbl.org, reject_rbl_client multihop.dsbl.org, reject_rbl_client argentina.blackholes.us, reject_rbl_client brazil.blackholes.us, reject_rbl_client china.blackholes.us, reject_rbl_client cn-kr.blackholes.us, reject_rbl_client hongkong.blackholes.us, reject_rbl_client japan.blackholes.us, reject_rbl_client korea.blackholes.us, reject_rbl_client malaysia.blackholes.us, reject_rbl_client mexico.blackholes.us, reject_rbl_client nigeria.blackholes.us, reject_rbl_client singapore.blackholes.us, reject_rbl_client taiwan.blackholes.us, reject_rbl_client thailand.blackholes.us, reject_rbl_client turkey.blackholes.us # tail /var/log/daemon # grep –i spam /var/log/maillog # spamdb | more spamdb –a xxx.xxx.xxx.xxx spamdb –d xxx.xxx.xxx.xxx /etc/postfix/master.cf smtp inet n - n - - smtpd smtp inet n - n - - smtpd -o content_filter=filter:dummy filter unix - n n - - pipe flags=R user=drweb argv=/usr/local/drweb/drweb-postfix -f ${sender} -- ${recipient} Строим виртуальную сеть с tinc Сергей Яремчук # ls -al /dev/net/tun # ls -al /dev/tap* alias char-major-10-200 tun # /sbin/depmod –a Code maturity level options [*] Prompt for development and/or incomplete code/drivers Network device support Universal tun/tap device driver support Файл tinc-up #!/bin/sh ifconfig $INTERFACE 192.168.10.1 netmask 255.255.0.0 Файл tinc-down #!/bin/sh ifconfig $INTERFACE down tinc 655/tcp TINC tinc 655/udp TINC vpn_net 192.168.10.0 # Sample tinc configuration file Name = office ConnectTo = home ConnectTo = stock-room Device = /dev/net/tun Name = home ConnectTo = office ConnectTo = stock-room Interface = VPN # Sample host configuration file Address = 10.10.1.67 Port = 655 Subnet = 192.168.10.0/24 -----BEGIN RSA PUBLIC KEY----- ... -----END RSA PUBLIC KEY----- # tincd -K -n vpn_net # tincd -n vpn_net FreeBSD tips: NAT по старинке Сергей Супрунов # natd –interface ed0 # ipfw add 100 divert natd ip from 192.168.0.0 to any out via ed0 # ipfw add 110 divert natd ip from any to 190.190.190.190 in via ed0natd_enable = “YES” natd_interface = “ed0” natd_flags = “-config /etc/natd.conf” Всегда на связи, или IP-роуминг: вводный курс Сергей Яремчук # mlrd-primary.rc # CN должны использовать аналогичное имя сети network_name my-tmip-mobility port 6554 foreground true log_file /var/log/mlrd.log status_file /var/log/mlrd.status logtrue # строка ниже указывает на вторичный MLR-сервер cc_mlr secondary.my-tmip-mobility.com:5555 # mlrd-secondary.rc network_name my-tmip-mobility port 5555 foreground true log_file /var/log/mlrd.log status_file /var/log/mlrd.status log true grant primary.my-tmip-mobility.com # /usr/local/sbin/mlrd -f mlrd-primary.rc # /usr/local/sbin/mlrd -f mlrd-secondary.rc # tmipd.rc mlr primary.my-tmip-mobility.com cn_name wlan. primary.my-tmip-mobility cn_if eth0 mobile_if wlan0 # или как вариант #mobile_if eth0 network_name my-tmip-mobility # следующая опция понадобится при запуске нескольких копий # CN на одном компьютере # tunnel_prefix tmip # разрешить регистрацию только занесенных в базу MLR-хостов registered_only false # чистка туннеля при запуске purge_tunnels true # так как CN занимается распределением адресов, # то реализована возможность задания диапазона addr_pool wlan0 * * # или как вариант # addr_pool eth1 10.10.15.32 +10.10.15.48 dns_server 10.10.15.7 debug_level 2 log true log_file /var/log/tmipd.log status_file /var/log/tmipd.status foreground true # pid_file /var/run/tmipd.pid # настройка сервера DHCP enable_dhcp true # domain_name my-tmip-mobility.com # dhcp_lease_time 300 # DHCP lease time in seconds # возможно игнорирование перемещения отдельных клиентов # ignore_mac aa:bb:cc:11:22:33 # /usr/local/sbin/tmipd -Ef tmipd.rc # /usr/local/sbin/tmipd # cat /var/log/tmipd.log # mlrp_query -M10.10.15.100 -A -m00:0D:18:01:1C:05 -p10.10.15.1 # /sbin/ifconfig wlan0 hw ether 00:0D:18:01:1C:05 Сага о биллинге, или Считаем трафик на FreeBSD (ng_ipacct + perl+ MySQL) Часть 1 Владимир Чижиков # cd /usr/src/sys/i386/conf/ # less LINT options NETGRAPH options NETGRAPH_ETHER options NETGRAPH_SOCKET options NETGRAPH_TEE # config SKIF # cd ../../compile/SKIF && make depend && make && make install && make clean && rehash # shutdown -r now # cd /usr/ports/ # make search key=ipacct # tar xfvz ng_ipacct-20040109.tar.gz # cd ng_ipacct/ # make && make install && make clean && rehash # ipacctctl rl0_ip_acct:rl0 checkpoint # ipacctctl rl0_ip_acct:rl0 show # ipacctctl rl0_ip_acct:rl0 clear ip_источника port_источника ip_назначения port_назначения протокол пакетов байт ip_источника ip_назначения пакетов байт # mkdir -p /usr/local/script/ng_stat # chown skif:wheel /usr/local/script/ng_stat # mkdir /usr/local/script/ng_stat/etc # mkdir /usr/local/script/ng_stat/bin # cd /usr/local/script/ng_stat/etc # Имя сервера, где находится база данных статистики server_db = freebsd # Имя базы данных, где будет сохраняться статистика db_name = ng_stat # Имя пользователя для доступа к базе db_user = nguser # Пароль для доступа к базе db_pass = rfn.if # Имя хоста, с которого снимается статистика listen_host = freebsd2 # Имена интерфейсов, которые прослушиваются на компьютере. # Указывать через запятую listen_interfaces = rl0 # cd /usr/local/script/ng_stat/bin # touch ng_stat_start.pl #!/usr/bin/perl -w ######################### # Список основных переменных ######################### my $serverdb = "test"; my $dbname = "test"; my $dbuser = "test"; my $dbpass = "test"; my $table_auth = "test"; my $table_proto = "test"; my $listen_host = "test"; my @listen_interf; open (CONFIG, "/usr/local/script/ng_stat/etc/ng_stat.conf"); while () { } close (CONFIG); $comment = '#'; if(/^$comment/) { print "Комментарий\n"; } else { # разбор строк, не ограниченных комментарием } ($param,$arg) = split("=",$_); chomp $param; chomp$arg; $param =~ s/\s//g; $arg =~ s/\s//g; $param =~ s/[\s\t]+//g; $arg =~ s/[\s\t]+//g; if ($param eq "server_db"){ $serverdb = $arg; } #!/usr/bin/perl -w use DBI; use POSIX ":sys_wait_h"; ######################### # Список основных переменных ######################### my $serverdb = "test"; my $dbname = "test"; my $dbuser = "test"; my $dbpass = "test"; my $table_auth = "test"; my $table_proto = "test"; my $listen_host = "test"; my @listen_interf; my $iface_set = "no"; my @ng_modules; my $ng_modules_def = "netgraph,ng_ether,ng_socket, ї ng_tee,ng_ipacct"; my$threshold = 5000; ######################### # Читаем конфигурационный файл. ######################### open (CONFIG, "/usr/local/script/ng_stat/etc/ng_stat.conf"); while () { $comment = '#'; if(/^$comment/) { # print "Коментарий\n"; } else { ($param,$arg) = split("=",$_); chomp $param; chomp $arg; my $razdel = ""; $param =~ s/[\s\t]+/$razdel/g; $arg =~ s/[\s\t]+/$razdel/g; if ($param eq "server_db"){ $serverdb = $arg; } if ($param eq "db_name"){ $dbname = $arg; } if ($param eq "db_user") { $dbuser = $arg; } if ($param eq "db_pass") { $dbpass = $arg; } if ($param eq "table_auth") { $table_auth = $arg; } if ($param eq "table_protocols") { $table_proto = $arg; } if ($param eq "listen_host") { $listen_host = $arg; } if ($param eq "listen_interfaces") { my $coma = ','; if (defined $arg) { $iface_set = "ok"; if ($arg ne ""){ if ($arg =~ m/$coma/ ) { @listen_interf=split($coma,$arg); } else { @listen_interf = $arg; } } } } if ($param eq "ng_modules") { my $coma = ','; if ($arg =~ m/$coma/ ){ @ng_modules = split($coma,$arg); } else { @ng_modules = split ($coma,$ng_modules_def); } } } } close (CONFIG); if (!defined $listen_interf[0]) { print "Установите, пожалуйста, в режим прослушивания хотя бы один интерфейс.\n"; } else { &check_kld_modules; &listening; } subcheck_kld_modules { my @modules; my $pid; my $ng_module_cfg; my $chk_ng_file = "/tmp/ng_file"; my $check_ng = 'kldstat -v | grep ng'; $check_ng = "$check_ng";# " > $chk_ng_file"; my $check_netgraph = 'kldstat -v | grep netgraph'; $check_netgraph = "$check_netgraph";#" >> $chk_ng_file"; # $pid = fork; @modules =split ("\n", `$check_ng && $check_netgraph`); my $mod; if (defined $modules[0]) { foreach my $modules (@modules) { $modules=~ s/\d+//g; if ($modules =~ s/.ko//g) { # } else { $modules =~ s/[\s\t]+//g; $mod = "$mod $modules "; } } chop $mod; foreach my $ng_modules (@ng_modules) { if ($mod=~m/$ng_modules/g){ # print "$mod содержит $ng_modules\n"; } else { my ($pid,$kid); $pid = fork; if (defined $pid) { if ($pid == 0){ print "Загрузка необходимого модуля ",$ng_modules,"\n"; exec "/sbin/kldload $ng_modules > /dev/null 2>&1" or die "Ошибка загрузки модуля $ng_modules !\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; } } } else { foreach my $ng_modules (@ng_modules) { my ($pid,$kid); $pid = fork; if (defined $pid) { if ($pid == 0){ print "Загрузка необходимого модуля ",$ng_modules,"\n"; exec "/sbin/kldload $ng_modules > /dev/null 2>&1" or die "Ошибка загрузки модуля $ng_modules !\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; } } } # kldstat -v @modules =split ("\n", `$check_ng && $check_netgraph`); $modules=~ s/\d+//g; if ($modules =~ s/.ko//g) { # } else { $modules =~ s/[\s\t]+//g; $mod = "$mod $modules "; } # Загружаемые модули NETGRAPH, необходимые для интерфейсов, # которые будет обслуживать программа. # По умолчанию загружаются следующие модули: netgraph, # ng_ether,ng_socket,ng_tee,ng_ipacct ng_modules = netgraph,ng_ether,ng_socket,ng_tee,ng_ipacct my@ng_modules; my$ng_modules_def = "netgraph,ng_ether,ng_socket, ng_tee,ng_ipacct"; if ($param eq "ng_modules") { my $coma = ','; if ($arg =~ m/$coma/ ){ @ng_modules = split($coma,$arg); } else { @ng_modules = split ($coma,$ng_modules_def); } foreach my $ng_modules (@ng_modules) { if ($mod=~m/$ng_modules/g){ # print "$mod содержит $ng_modules\n"; } else { my $pid; $pid = fork; if (defined $pid) { if ($pid == 0){ print "Загрузка необходимого модуля ",$ng_modules,"\n"; exec "/sbin/kldload $ng_modules > /dev/null 2>&1" or die "Ошибка загрузки модуля $ng_modules !\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; undef $pid; } } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; my $threshold = 5000; # Отнеситесь внимательно к выбору этого параметра. # Он указывает, сколько записей будет храниться в буфере # По умолчанию значение равно 5000, но если у вас меньше # 128 Мб памяти – уменьшите его. Значение во многом # зависит от того, какая полоса пропускания на вашем канале, # и от того насколько он загружен. Для 128 Кб и 64 Мб # можно будет смело установить и 10000 записей, при условии # снятия cтатистики хотя бы раз в 15-20 минут. Для канала # в 2 Мбита этого времени будет уже слишком много threshold = 5000 if ($param eq "threshold") { $threshold = $arg; } sub listening{ my $pid; $ngctl = "/usr/sbin/ngctl"; $ipacctctl = "/usr/local/sbin/ipacctctl"; while (@listen_interf){ $interface = shift @listen_interf; #/usr/sbin/ngctl mkpeer ${IFACE}: tee lower right $mkpeer = "$ngctl mkpeer $interface\: tee lower right"; $pid = fork; if (defined $pid) { ($pid == 0){ print "Создание и подключение нового NETGRAPH-узла к уже существующему:\n $mkpeer\n"; exec "$mkpeer" or die "Ошибка создания нового узла NETGRAPH!\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; #/usr/sbin/ngctl connect ${IFACE}: lower upper left $connect = "$ngctl connect $interface\: lower upper left"; $pid = fork; if (defined $pid) { if ($pid == 0){ print "Соединение двух NETGRAPH-узлов на интерфейсе:\n$connect\n"; exec "$connect" or die "Ошибка соединения двух NETGRAPH-узлов!\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; #/usr/sbin/ngctl name ${IFACE}:lower ${IFACE}_acct_tee $name = "$ngctl name $interface\:lower $interface\_acct_tee "; $pid = fork; if (defined $pid) { ($pid == 0){ print "Присвоение имени созданному узлу:\n$name\n"; exec "$name" or die "Ошибка на этапе присвоения имени созданному узлу!\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; #/usr/sbin/ngctl mkpeer ${IFACE}_acct_tee: ipacct right2left ${IFACE}_in $mkpeer = "$ngctl mkpeer $interface\_acct_tee: ipacct right2left $interface\_in"; $pid = fork; if (defined $pid) { ($pid == 0){ print "Создание и подключение нового NETGRAPH-узла к уже существующему:\n $mkpeer\n"; exec "$mkpeer" or die "Ошибка создания нового узла NETGRAPH!\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; #/usr/sbin/ngctl name ${IFACE}_acct_tee:right2left ${IFACE}_ip_acct $name = "$ngctl name $interface\_acct_tee:right2left $interface\_ip_acct"; $pid = fork; if (defined $pid) { ($pid == 0){ print "Присвоение имени созданному узлу:\n$name\n"; exec "$name" or die "Ошибка на этапе присвоения имени созданному узлу!\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; #/usr/sbin/ngctl connect ${IFACE}_acct_tee: ${IFACE}_ip_acct: left2right ${IFACE}_out $connect = "$ngctl connect $interface\_acct_tee: $interface\_ip_acct: left2right $interface\_out"; $pid = fork; if (defined $pid) { if ($pid == 0){ print "Соединение двух NETGRAPH-узлов на интерфейсе:\n$connect\n"; exec "$connect" or die "Ошибка соединения двух NETGRAPH-узлов!\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; #$IPACCTCTL ${IFACE}_ip_acct:$IFACE verbose $VERBOSE $verbose = "$ipacctctl ї $interface\_ip_acct:$interface verbose 1"; $pid = fork; if (defined $pid) { ($pid == 0){ print "Установка режима вывода информации:\n$verbose\n"; exec "$verbose" or die "Ошибка установки режима вывода информации\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; #$IPACCTCTL ${IFACE}_ip_acct:$IFACE threshold $THRESHOLD $set_threshold = "$ipacctctl $interface\_ip_acct:$interface threshold $threshold"; $pid = fork; if (defined $pid) { if ($pid == 0){ print "Установка THRESHOLD:\n$set_threshold\n"; exec "$set_threshold" or die "Ошибка установки параметра THRESHOLD\n"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; } } # sudo ./ng_stat_start.pl if (!defined $listen_interf[0]) { print "Установите, пожалуйста, в режим прослушивания хотя бы один интерфейс.\n"; } else { foreach my $interface (@listen_interf){ #/usr/sbin/ngctl shutdown ${IFACE}_acct_tee: $shutdown = "$ngctl shutdown $interface\_acct_tee:"; my $pid; $pid = fork; if (defined $pid) { ($pid == 0){ print "Отключение созданных узлов на интерфейсе:\n$shutdown\n"; exec "$shutdown"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; # sleep 1; $shutdown = "$ngctl shutdown $interface\:"; $pid = fork; if (defined $pid) { if ($pid == 0){ print "Отключение NETGRAPH на интерфейсе:\n$shutdown\n"; exec "$shutdown"; exit; } } else { print "Фатальная ошибка ветвления!\n.................\n"; die "Разделение на процессы невозможно.\n Принудительный выход из дочернего процесса: $!\n"; } do { $kid = waitpid $pid,0; if ($kid == -1) { print "Дочерних процессов в системе нет или система не поддерживает их.\n Ошибка!" and die "Выход!\n"; } elsif ($kid == 0) { print "Задан не блокирующий вызов и процесс еще не завершен!\n"; } } until $kid=$pid; undef $pid; } } #!/bin/sh case "$1" in start) /usr/local/script/ng_stat/bin/ng_stat_start.pl echo"ng_stat" ;; stop) /usr/local/script/ng_stat/bin/ng_stat_stop.pl ;; *) echo "" echo "Usage: `basename $0` { start | stop }" "" ;; esac Автоматическая установка ОС и сопутствующего программного обеспечения Иван Коробко [разделM] параметр1M=значение1M параметр2M=значение2M ………………………. параметрNM=значениеNM «winnt[32] /u:<файл ответов>»; C:\BOOTCD\SERVICEPACK\XP-SP1.EXE /U /X:C:\BOOTCD\SERVICEPACK C:\BOOTCD\SERVICEPACK\UPDATE.EXE /S:C:\BOOTCD\WINDOWS Q######_XXX_YYY_ZZZ _LLL.exe [Unattended] OEMPreinstall=Yes [GuiRunOnce] " C\Install\HotFix\Q######.exe /n /q /z" "%WinDir%\System32\Cmd.exe /c RmDir C\Install /s /q" Q######.exe /q /n /z C:\BOOTCD\MUI\MUI_RUS.EXE /U /X:C:\BOOTCD\MUI [GuiRunOnce] "c:\MUIINST\MUISETUP.EXE /i 0419 /d 0419 /r /s" "%windir%\system32\cmd.exe /c rmdir c:\MUIINST /s/q" [Unattended] OemPnPDriversPath=drivers\video;drivers\sound DriverSigningPolicy=Ignore OEMPreinstall=Yes c:\Install\NAV\setup.exe /qn C:\Install\Wrar\Wrar340ru.exe /s regedit /s c:\Install\WRar\wrar.reg c:\Install\Nero\Nero551054.exe /silent /noreboot /sn=xxxx-xxxx-xxxx-xxxx-xxxx-xxxx /write_sn Regedit /S c:\Install\Nero\nero.reg c:\Install\Nero\Nero551054.exe /silent /noreboot Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Ahead\Nero - Burning Rom\Info] "User"="UserName" "Company"="CompanyName" "Serial6"=" xxxx-xxxx-xxxx-xxxx-xxxx-xxxx " C:\Install\Areader\Areader.msi /qb Pro11.msi /qb Setup.exe /qb Pro11.msi Transforms=FileName.mst /qb Setup.exe Transforms=FileName.mst /qb Office2003SP1-KB842532-fullfile-enu.exe /q /c /t:С:\Office2003\SP1 MsiExec /p C:\Office2003\SP1\MainSp1f.msp /a C:\Office2003\Office\Pro11.msi ShortFileNames=True /qb MsiExec /p C:\Office2003\SP1\Owc11Sp1ff.msp /a C:\Office2003\Office\OWC11.msi ShortFileNames=True /qb XXX_KB######_YYY_ZZZ.exe Office2003_KB######_FullFile_Enu.exe C:\Install\Office\setup.exe transforms= C:\Install\Office\answer.mst /qb- /noreboot Техника оптимизации под Linux Крис Касперски Листинг 1. Не оптимизированный кандидат на объединение констант printf("hello,world!\n"); // одна строковая константа printf("hello,world!\n"); // другая константа, идентичная первой printf("i say hello, world!\n"); // константа с идентичной подстрокой Листинг 2. Частично оптимизированный вариант char s[]="i say hello, world!\n"; // размещаем строку в памяти printf(&s[6]); // выводим подстроку printf(&s[6]); // выводим подстроку printf(s); // выводим всю строку целиком Листинг 3. Полностью оптимизированный вариант char *s1 = "I say hello,world!\n"; char *s2 = s1+sizeof("I say ")-1; //"hello, world!\n" printf(s2); printf(s2); printf(s1); Листинг 4. Кандидат на константную подстановку f1(int a, int b) { return a+b; } f2 () { return f1(0x69, 0x96) + 0x666; } Листинг 5. Пример программы с неиспользуемыми переменными main(int n, char **v) { int a,b,c; a =n; b = a + 1; c = 6*b; // переменная c не используется, а значит переменные a и b лишние return n; } Листинг 6. Пример программы с неиспользуемыми выражениями main(int n, char** v) { int a,b; a = n+0x666; // не используется, перекрывается (2*n) b = n-0x999; // теряется при выходе из функции a = 2*n; // единственное используемое выражение return a; } Листинг 7. Пример с лишними обращениями к памяти, от которых нельзя избавиться f(int *a, int *b) { int x; x = *a + *b; // сложение содержимого двух ячеек *b = 0x69; // изменение ячейки *b, адрес которой не известен компилятору x += *a; // нет гарантии, что запись в ячейку *b не изменила ячейку *a } Листинг 8. Пример с лишними обращениями к памяти, от которых можно избавиться вручную f(char *x, int *dst, int n) { int i; for (i = 0; i < n; i++) *dst += x[i]; } Листинг 9. Оптимизированный вариант f(char *x, int *dst, int n) { int i,t =0; for (i=0;icurrent != 1) return -1; /* Определяем текущий профиль */ *((__u8 *)&cur_prof) = data_buff[7]; *((__u8 *)&cur_prof + 1) = data_buff[6]; printf("\nТекущий профиль - 0x%04X\n", cur_prof); /* Возвращаем значение бита SAO */ return (cd_sao->sao); } /* Глобальные переменные */ __u16 page5_len; __u8 *page5_data; wpm_t *wpm; // данные страницы параметров записи int mode_sense() { __u8 mode_sense_cmd[10]; test_unit_ready(); /* Определяем размер страницы параметров записи – первые два байта блока данных, * возвращаемых устройством по команде MODE_SENSE */ page5_data = (__u8 *)malloc(2); memset(mode_sense_cmd, 0, 10); mode_sense_cmd[0] = MODE_SENSE_10; mode_sense_cmd[2] = 5; // страница параметров записи mode_sense_cmd[8] = 2; send_cmd(mode_sense_cmd, 10, SG_DXFER_FROM_DEV, page5_data, 2, 200); *((__u8 *)&page5_len) = page5_data[1]; *((__u8 *)&page5_len + 1) = page5_data[0]; page5_len += 2; printf("Размер страницы параметров записи – %d байт\n", page5_len); free(page5_data); /* Размер страницы параметров режима записи известен, выделяем память для страницы */ page5_data = (__u8 *)malloc(page5_len); memset(page5_data, 0, page5_len); /* Структура wpm_t *wpm хранит данные страницы параметров записи, ее формат был рассмотрен в [2]. wpm указывает * на начало страницы параметров режима записи */ wpm = (void *)(page5_data + 8); /* Формируем команду MODE_SENSE_10 */ memset(mode_sense_cmd, 0, 10); mode_sense_cmd[0] = MODE_SENSE_10; mode_sense_cmd[2] = 5; // страница параметров записи mode_sense_cmd[8] = page5_len; send_cmd(mode_sense_cmd, 10, SG_DXFER_FROM_DEV, page5_data, page5_len, 200); return 0; } int mode_select() { __u8 mode_select_cmd[10]; /* Считываем страницу параметров режима записи */ mode_sense(); /* Устанавливаем необходимый режим */ wpm->write_type = 2; // режим SAO wpm->multises = 0; // односессионный диск test_unit_ready(); /* Формируем команду MODE_SELECT_10 */ memset(mode_select_cmd, 0, 10); mode_select_cmd[0] = MODE_SELECT_10; mode_select_cmd[1] = 0x10; mode_select_cmd[7] = *((__u8 *)&page5_len + 1); mode_select_cmd[8] = *(__u8 *)&page5_len; if(send_cmd(mode_select_cmd, 10, SG_DXFER_TO_DEV, page5_data, page5_len, 200) < 0) return -1; free(page5_data); return 0; } M = IP((LBA + 150) / (60 * 75)) S = IP((LBA + 150 - M * 60 * 75) / 75) F = IP(LBA + 150 - M * 60 *7 5 - S * 75) #define LBA2MIN(LBA) ((LBA + 150) / (60 * 75)) #define LBA2SEC(LBA, MIN) ((LBA + 150 - (MIN * 60 * 75)) / 75) #define LBA2FRAME(LBA, MIN, SEC) ((LBA + 150 - (MIN * 60 * 75)) - (SEC * 75)) int send_cue_sheet(__u32 trk_size) { __u8 cue_sheet_cmd[10]; __u8 cue_buff[32]; // структура CUE SHEET, размер 32 байта __u8 min, sec, frame; // координаты Lead-Out-области memset(cue_sheet_cmd, 0, 10); memset(buff, 0, 32); /* Заполняем поля CUE SHEET. Начинаем с Lead-In-области */ cue_buff[0] = 0x01; // CTL/ARD cue_buff[1] = 0x00; // номер трека, всегда 0 cue_buff[2] = 0x00; // индекс трека, всегда 0 cue_buff[3] = 0x01; // DATA FORM, всегда 1 cue_buff[4] = 0x00; // SCMS cue_buff[5] = 0x00; // Minute = 0 cue_buff[6] = 0x00; // Second = 0 cue_buff[7] = 0x00; // Frame = 0 /* Pre-gap область первого трека */ cue_buff[8] = 0x41; // CTL = 4 – трек содержит данные cue_buff[9] = 0x01; // номер трека = 1 cue_buff[10] = 0x00; // индекс трека = 0 cue_buff[11] = 0x10; // данные в формате Mode 1 cue_buff[12] = 0x00; // SCMS /* Координаты Pre-Gap-области – (-150) в формате LBA, или 0/0/0 в MSF-формате */ cue_buff[13] = 0x00; // Minute cue_buff[14] = 0x00; // Second cue_buff[15] = 0x00; // Frame /* Первый трек */ cue_buff[16] = 0x41; // CTL = 4 – трек содержит данные cue_buff[17] = 0x01; // номер трека = 1 cue_buff[18] = 0x01; // индекс трека = 1 cue_buff[19] = 0x10; // данные в формате Mode 1 cue_buff[20] = 0x00; // SCMS /* Координаты первого трека – 0 в формате LBA, или 0/2/0 в MSF-формате */ cue_buff[21] = 0x00; // Minute cue_buff[22] = 0x02; // Second cue_buff[23] = 0x00; // Frame /* Lead-Out */ cue_buff[24] = 0x01; // CTL/ADR cue_buff[25] = 0xAA; // номер трека выходной области cue_buff[26] = 0x01; // индекс, для Lead-Out всегда 1 cue_buff[27] = 0x01; // DATA FORM, всегда 1 cue_buff[28] = 0x00; // SCMC /* Определяем координаты Lead-Out-области. Эта область расположена сразу за первым треком. * Размер трека нам известен */ min = LBA2MIN(trk_size); sec = LBA2SEC(trk_size, min); frame = LBA2FRAME(trk_size, min, sec); printf("\nMIN/SEC/FRAME: %.2d/%.2d/%.2d\n", min, sec, frame); cue_buff[29] = min; cue_buff[30] = sec; cue_buff[31] = frame; /* Формируем команду SEND CUE SHEET */ cue_sheet_cmd[0] = 0x5D; cue_sheet_cmd[8] = 32; if(send_cmd(cue_sheet_cmd, 10, SG_DXFER_TO_DEV, cue_buff, 32, 200) < 0) return -1; return 0; } int write_iso(__u8 *file_name) { #define PREGAP_SIZE 307200 // размер Pre-Gap-области: 150 секторов по 2048 байт int ret, in_f; __u8 write_cmd[10]; __u8 *write_buff; int lba, lba1 = -150; in_f = open(file_name, O_RDONLY); memset(write_cmd, 0, 10); write_cmd[0] = WRITE_10; write_cmd[8] = 150; // размер Pre-Gap в секторах write_buff = (__u8 *)malloc(PREGAP_SIZE); memset(write_buff, 0, PREGAP_SIZE); /* Записываем Pre-gap-область. Она начинается с сектора – 150 и содержит нули */ lba = __swab32(lba1); memcpy((write_cmd + 2), (void *)&lba, 4); lba1 += 150; while(1) { ret = send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, write_buff, PREGAP_SIZE, 200); if(ret == 0) break; if(ret < 0) return -1; } free(write_buff); /* Дальше выполняется запись данных первого трека аналогично рассмотренным ранее примерам (см. [2]) */ . . . . . . . } int send_cmd(__u8 *cmd, __u8 cmdlen, int direction, __u8 *data, __u32 datalen, unsigned int timeout) { ............ rep: if(ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("SG_IO ioctl"); return -1; } if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) { if(io_hdr.sb_len_wr > 0) { /* Если SK/ASC/ASCQ == 02/04/08 (Not Ready. Long Write in Progress), то необходимо повторить команду WRITE_10 */ if((SK == NOT_READY) && (ASC == 0x04) && (ASCQ == 0x08)) goto rep; ........... } LOCAL void fillcue(cp, ca, tno, idx, dataform, scms, mp) struct mmc_cue *cp; /* The target cue entry */ int ca; /* Control/adr for this entry */ int tno; /* Track number for this entry */ int idx; /* Index for this entry */ int dataform; /* Data format for this entry */ int scms; /* Serial copy management */ msf_t *mp; /* MSF value for this entry */ { cp->cs_ctladr = ca; /* XXX wie lead in */ cp->cs_tno = tno; cp->cs_index = idx; cp->cs_dataform = dataform;/* XXX wie lead in */ cp->cs_scms = scms; cp->cs_min = mp->msf_min; cp->cs_sec = mp->msf_sec; cp->cs_frame = mp->msf_frame; /* Этот код добавлен нами в учебных целях! */ printf("\n0x%.2X\t", cp->cs_ctladr); printf("0x%.2X\t",cp->cs_tno); printf("0x%.2X\t",cp->cs_index); printf("0x%.2X\t",cp->cs_dataform); printf("0x%.2X\t",cp->cs_scms); printf("0x%.2X\t",cp->cs_min); printf("0x%.2X\t",cp->cs_sec); printf("0x%.2X\n",cp->cs_frame); } # cdrecord -dev=X,Y,Z -dao -pad -audio trk1.wav rk2.wav trk3.wav int send_cue_sheet(int trk1_size, int trk2_size, int trk3_size) { __u8 cue_sheet_cmd[10]; __u8 *cue_buff; __u8 min, sec, frame; int cb_size = 0; int trk = -150; /* Определяем размер структуры CUE SHEET. В ее состав входят три Pre-Gap-области, три трека, * входная и выходная области */ cb_size = 3 * 8 + 3 * 8 + 16; // Итого 64 байта cue_buff = (__u8 *)malloc(cb_size); memset(cue_sheet_cmd, 0, 10); memset(cue_buff, 0, cb_size); /* Формируем Lead-In-область */ cue_buff[0] = 0x01; cue_buff[1] = 0x00; cue_buff[2] = 0x00; cue_buff[3] = 0x01; cue_buff[4] = 0x00; cue_buff[5] = 0x00; cue_buff[6] = 0x00; cue_buff[7] = 0x00; /* Pre-gap первого трека */ cue_buff[8] = 0x01; cue_buff[9] = 0x01; cue_buff[10] = 0x00; cue_buff[11] = 0x00; cue_buff[12] = 0x00; cue_buff[13] = 0x00; cue_buff[14] = 0x00; cue_buff[15] = 0x00; /* Первый трек */ cue_buff[16] = 0x01; cue_buff[17] = 0x01; cue_buff[18] = 0x01; cue_buff[19] = 0x00; cue_buff[20] = 0x00; cue_buff[21] = 0x00; cue_buff[22] = 0x02; cue_buff[23] = 0x00; /* Pre-gap-область второго трека захватывает последние 150 секторов первого трека */ trk += trk1_size; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); cue_buff[24] = 0x01; cue_buff[25] = 0x02; cue_buff[26] = 0x00; cue_buff[27] = 0x00; cue_buff[28] = 0x00; cue_buff[29] = min; cue_buff[30] = sec; cue_buff[31] = frame; /* Второй трек расположен сразу за первым, т.е. пауза между треками отсутствует */ sec += 2; // длина Pre-Gap – 2 секунды, или 150 секторов cue_buff[32] = 0x01; cue_buff[33] = 0x02; cue_buff[34] = 0x01; cue_buff[35] = 0x00; cue_buff[36] = 0x00; cue_buff[37] = min; cue_buff[38] = sec; cue_buff[39] = frame; /* Pre-gap-область третьего трека захватывает последние 150 секторов второго трека */ trk += trk2_size; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); cue_buff[40] = 0x01; cue_buff[41] = 0x03; cue_buff[42] = 0x00; cue_buff[43] = 0x00; cue_buff[44] = 0x00; cue_buff[45] = min; cue_buff[46] = sec; cue_buff[47] = frame; /* Третий трек */ sec += 2; cue_buff[48] = 0x01; cue_buff[49] = 0x03; cue_buff[50] = 0x01; cue_buff[51] = 0x00; cue_buff[52] = 0x00; cue_buff[53] = min; cue_buff[54] = sec; cue_buff[55] = frame; /* Lead-Out-область */ trk += trk3_size + 150; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); cue_buff[56] = 0x01; cue_buff[57] = 0xAA; cue_buff[58] = 0x01; cue_buff[59] = 0x01; cue_buff[60] = 0x00; cue_buff[61] = min; cue_buff[62] = sec; cue_buff[63] = frame; /* Формируем командный пакет */ cue_sheet_cmd[0] = 0x5D; cue_sheet_cmd[8] = cb_size; /* Отправляем устройству команду SEND_CUE_SHEET, освобождаем память и выходим из функции */ if(send_cmd(cue_sheet_cmd, 10, SG_DXFER_TO_DEV, cue_buff, cb_size, 200) < 0) return -1; free(cue_buff); return 0; } int write_audio(__u8 *file_name, int flag) { #define PREGAP_SIZE 352800 // 150 секторов по 2352 байта int ret, i; int in_f; __u8 write_cmd[10]; __u8 *write_buff; int lba = 0; static int lba1 = -150; // стартовый адрес для записи in_f = open(file_name, O_RDONLY); /* Перешагиваем через WAV-заголовок */ lseek(in_f, 44, 0); memset(write_cmd, 0, 10); write_cmd[0] = WRITE_10; if(flag == 1) { // записываем первый трек write_buff = (__u8 *)malloc(PREGAP_SIZE); memset(write_buff, 0, PREGAP_SIZE); write_cmd[8] = 150; /* Записываем Pre-gap-область первого трека */ lba = __swab32(lba1); memcpy((write_cmd + 2), (void *)&lba, 4); lba1 += 150; while(1) { ret = send_cmd(write_cmd, 10, SG_DXFER_TO_DEV, write_buff, PREGAP_SIZE, 200); if(ret == 0) break; if(ret < 0) return 0; } free(write_buff); } /* Дальше выполняется запись данных аудиотрека */ . . . . . . . } int send_cue_sheet(int trk1_size, int trk2_size, int trk3_size) { __u8 cue_sheet_cmd[10]; __u8 *cue_buff; __u8 min, sec, frame; int cb_size = 0; int trk = 0; /* Вычисляем размер CUE SHEET – Pre-Gap-область первого трека, три трека, Lead-In- и Lead-Out-области */ cb_size = 3 * 8 + 8 + 16; // Итого 48 байт cue_buff = (__u8 *)malloc(cb_size); memset(cue_sheet_cmd, 0, 10); memset(cue_buff, 0, cb_size); /* Описание Lead-In-области, Pre-gap-области первого трека и непосредственно первого трека точно такие же, * как и в предыдущем примере */ /* Lead-In-область */ ....... /* Pre-gap первого трека */ ....... /* Первый трек */ ....... /* Второй трек */ trk += trk1_size; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); cue_buff[24] = 0x01; cue_buff[25] = 0x02; cue_buff[26] = 0x01; cue_buff[27] = 0x00; cue_buff[28] = 0x00; cue_buff[29] = min; cue_buff[30] = sec; cue_buff[31] = frame; /* Третий трек */ trk += trk2_size; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); cue_buff[32] = 0x01; cue_buff[33] = 0x03; cue_buff[34] = 0x01; cue_buff[35] = 0x00; cue_buff[36] = 0x00; cue_buff[37] = min; cue_buff[38] = sec; cue_buff[39] = frame; /* Lead-Out */ trk += trk3_size; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); cue_buff[40] = 0x01; cue_buff[41] = 0xAA; cue_buff[42] = 0x01; cue_buff[43] = 0x01; cue_buff[44] = 0x00; cue_buff[45] = min; cue_buff[46] = sec; cue_buff[47] = frame; cue_sheet_cmd[0] = 0x5D; cue_sheet_cmd[8] = cb_size; if(send_cmd(cue_sheet_cmd, 10, SG_DXFER_TO_DEV, cue_buff, cb_size, 200) < 0) return -1; free(cue_buff); return 0; } int send_cue_sheet(char **argv, int trk_num) { int i = 0, n; __u8 cue_sheet_cmd[10]; __u8 *cue_buff = NULL; __u8 min, sec, frame; struct stat s; int cb_size = 0; int trk = 0; cb_size = trk_num * 8 + 8 + 16; cue_buff = (__u8 *)malloc(cb_size); memset(cue_sheet_cmd, 0, 10); memset(cue_buff, 0, cb_size); /* Lead-In-область, Pre-gap первого трека, первый трек (см. предыдущий пример) */ ....... /* Записываем в структуру CUE SHEET информацию о треках. Начинаем со второго трека, т.к. для первого * запись уже сформирована */ for(i = 1, n = 24; i < trk_num; i++, n += 8) { /* Определяем размер трека */ memset((void *)&s, 0, sizeof(struct stat)); stat(argv[i], &s); /* Стартовые координаты трека */ trk += s.st_size/CD_FRAMESIZE_RAW; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); /* Формируем в структуре CUE SHEET запись для трека */ cue_buff[n] = 0x01; cue_buff[n + 1] = i + 1; cue_buff[n + 2] = 0x01; cue_buff[n + 3] = 0x00; cue_buff[n + 4] = 0x00; cue_buff[n + 5] = min; cue_buff[n + 6] = sec; cue_buff[n + 7] = frame; } /* Определяем размер последнего трека */ memset((void *)&s, 0, sizeof(struct stat)); stat(argv[trk_num], &s); /* Формируем Lead-Out-область */ trk += s.st_size/CD_FRAMESIZE_RAW; min = LBA2MIN(trk); sec = LBA2SEC(trk, min); frame = LBA2FRAME(trk, min, sec); cue_buff[n] = 0x01; cue_buff[n + 1] = 0xAA; cue_buff[n + 2] = 0x01; cue_buff[n + 3] = 0x01; cue_buff[n + 4] = 0x00; cue_buff[n + 5] = min; cue_buff[n + 6] = sec; cue_buff[n + 7] = frame; cue_sheet_cmd[0] = 0x5D; cue_sheet_cmd[8] = cb_size; if(send_cmd(cue_sheet_cmd, 10, SG_DXFER_TO_DEV, cue_buff, cb_size, 200) < 0) return -1; free(cue_buff); return 0; } unformat для NTFS Крис Касперски Листинг 1. Командный файл для ручного восстановления $MFT из $MFTMirr, XXX – номер сектора $MFTMirr, YYY – номер сектора $MFT SECINSPECT.EXE -backup d: backup.dsk XXX 1 SECINSPECT.EXE –restore d: backup.dsk YYY CONFIRM