/l3/users/su/mrg/mrgar.mrg.com/su :1 :2 :3 :4 :5 :6 :7 :8 :9 :10 :11 :12 :13 :14 :15 :16 :17 :18 :19 :20 :21 :22 :23 :24 :25 :26 :27 :28 :29 :30 :31 :32 :33 :34 :35 :36 :37 :38 :39 :40 |
|
#which screeb
![]() which: no screeb in (/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin) |
#which screen
![]() /usr/bin/screen |
#cd /usr/bin/
|
#chmod +x script
|
$w
11:18:55 up 3 days, 19:35, 3 users, load average: 0,39, 0,62, 0,55 USER TTY LOGIN@ IDLE JCPU PCPU WHAT su pts/2 11:14 3:26 0.03s 0.03s script -f -c bash -q /home/su/.lilalo/ su pts/255 10:09 13.00s 0.08s 0.02s sshd: su [priv] su pts/5 11:18 0.00s 0.02s 0.02s script -f -c bash -q /home/su/.lilalo/ |
$w
13:22:12 up 21:38, 1 user, load average: 0,70, 0,42, 0,37 USER TTY LOGIN@ IDLE JCPU PCPU WHAT su pts/0 13:22 0.00s 0.02s 0.02s script -f -c bash -q /home/su/.lilalo/ |
$w
13:22:16 up 21:38, 1 user, load average: 0,65, 0,41, 0,37 USER TTY LOGIN@ IDLE JCPU PCPU WHAT su pts/0 13:22 0.00s 0.02s 0.02s script -f -c bash -q /home/su/.lilalo/ |
$l3 pwd
/users/su/mrg/mrgar.mrg.com/su |
$sudo su
|
#w
![]() 13:24:44 up 21:41, 1 user, load average: 0.23, 0.36, 0.35 USER TTY LOGIN@ IDLE JCPU PCPU WHAT su pts/0 13:22 0.00s 0.02s 0.02s script -f -c bash -q /home/su/.lilalo/ |
#w
13:24:44 up 21:41, 1 user, load average: 0.23, 0.36, 0.35 USER TTY LOGIN@ IDLE JCPU PCPU WHAT su pts/0 13:22 0.00s 0.02s 0.02s script -f -c bash -q /home/su/.lilalo/ |
#l
![]() total 510 -rw-r--r-- 1 root root 564 Sep 9 13:24 .monit.state -rw-r--r-- 1 root root 38 Sep 9 13:15 .l3rc drwxr-xr-x 2 root root 272 Sep 9 11:38 .lilalo/ -rw------- 1 root root 3450 Sep 9 11:37 .bash_history drwx------ 16 root root 1120 Sep 9 11:37 ./ -rw------- 1 root root 563 Sep 9 11:37 .bashrc -rw------- 1 root root 943 Sep 9 11:37 .viminfo -rw-r--r-- 1 root root 116 Sep 9 11:00 .bash_profile drwx------ 2 root root 144 Sep 9 10:57 tmp/ ... drwx------ 2 root root 144 Feb 11 2008 .kde/ drwxr-xr-x 2 root root 80 Feb 5 2008 .kbd/ drwx------ 2 root root 168 Feb 5 2008 .install-log/ -rw-r--r-- 1 root root 1973 Feb 5 2008 autoinstall.scm -rw------- 1 root root 24 Jan 9 2008 .bash_logout -rw------- 1 root root 218 Jan 9 2008 .cshrc -rw------- 1 root root 240 Jan 9 2008 .i18n -rw------- 1 root root 45 Jan 9 2008 .rpmmacros -rw------- 1 root root 174 Jan 9 2008 .tcshrc -rw------- 1 root root 598 Jan 9 2008 .zshrc |
#l
total 510 -rw-r--r-- 1 root root 564 Sep 9 13:24 .monit.state -rw-r--r-- 1 root root 38 Sep 9 13:15 .l3rc drwxr-xr-x 2 root root 272 Sep 9 11:38 .lilalo/ -rw------- 1 root root 3450 Sep 9 11:37 .bash_history drwx------ 16 root root 1120 Sep 9 11:37 ./ -rw------- 1 root root 563 Sep 9 11:37 .bashrc -rw------- 1 root root 943 Sep 9 11:37 .viminfo -rw-r--r-- 1 root root 116 Sep 9 11:00 .bash_profile drwx------ 2 root root 144 Sep 9 10:57 tmp/ ... drwx------ 2 root root 144 Feb 11 2008 .kde/ drwxr-xr-x 2 root root 80 Feb 5 2008 .kbd/ drwx------ 2 root root 168 Feb 5 2008 .install-log/ -rw-r--r-- 1 root root 1973 Feb 5 2008 autoinstall.scm -rw------- 1 root root 24 Jan 9 2008 .bash_logout -rw------- 1 root root 218 Jan 9 2008 .cshrc -rw------- 1 root root 240 Jan 9 2008 .i18n -rw------- 1 root root 45 Jan 9 2008 .rpmmacros -rw------- 1 root root 174 Jan 9 2008 .tcshrc -rw------- 1 root root 598 Jan 9 2008 .zshrc |
#cat .bashrc
![]() # .bashrc # User specific aliases and functions alias cp='cp -i' alias mv='mv -i' alias rm='rm -i' alias d='ls' alias s='cd ..' alias p='cd -' # Read /etc/inputrc if the variable is not defined. [ -n "$INPUTRC" ] || export INPUTRC=/etc/inputrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi PATH=/root/bin:/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin ENV=$HOME/.bashrc USERNAME="root" export USERNAME ENV PATH #[ $0 == l3script ] && . /root/.lilalo/l3bashrc && _l3_start . ${user_home}/.lilalo/l3bashrc && _l3_start |
#cat .bashrc
# .bashrc # User specific aliases and functions alias cp='cp -i' alias mv='mv -i' alias rm='rm -i' alias d='ls' alias s='cd ..' alias p='cd -' # Read /etc/inputrc if the variable is not defined. [ -n "$INPUTRC" ] || export INPUTRC=/etc/inputrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi PATH=/root/bin:/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin ENV=$HOME/.bashrc USERNAME="root" export USERNAME ENV PATH #[ $0 == l3script ] && . /root/.lilalo/l3bashrc && _l3_start . ${user_home}/.lilalo/l3bashrc && _l3_start |
#vim .bashrc
![]() --- /tmp/l3-saved-11499.5991.12403 2011-09-09 13:25:15 +0400 +++ .bashrc 2011-09-09 13:25:21 +0400 @@ -21,4 +21,4 @@ USERNAME="root" export USERNAME ENV PATH #[ $0 == l3script ] && . /root/.lilalo/l3bashrc && _l3_start -. ${user_home}/.lilalo/l3bashrc && _l3_start +#. ${user_home}/.lilalo/l3bashrc && _l3_start |
#ps fax | grep script
![]() 11156 pts/0 Ss+ 0:00 \_ script -f -c bash -q /home/su/.lilalo//326433028 11232 pts/0 S+ 0:00 \_ script -f -c bash -q /home/su/.lilalo//32643 11467 pts/1 S+ 0:00 \_ script -f -c bash -q /home/su/.l 11498 pts/1 S+ 0:00 \_ script -f -c bash -q /home/s 11703 pts/2 S+ 0:00 \_ grep script |
#ps fax | grep script
11156 pts/0 Ss+ 0:00 \_ script -f -c bash -q /home/su/.lilalo//326433028 11232 pts/0 S+ 0:00 \_ script -f -c bash -q /home/su/.lilalo//32643 11467 pts/1 S+ 0:00 \_ script -f -c bash -q /home/su/.l 11498 pts/1 S+ 0:00 \_ script -f -c bash -q /home/s 11703 pts/2 S+ 0:00 \_ grep script |
$killall l3-agent
![]() l3-agent: не завершён ни один процесс |
$cd .l
![]() .l3rc .lesshst .lftp/ .lilalo/ .lpoptions |
$cd .lilalo/
|
$l;
итого 122 -rw-r--r-- 1 su su 664 Сен 9 13:26 268158378436214913-1315560387.info -rw-r--r-- 1 su su 1165 Сен 9 13:26 268158378436214913-1315560387.script drwxr-xr-x 2 su root 576 Сен 9 13:26 ./ -rw-r--r-- 1 su su 194 Сен 9 13:26 .report.dat -rw-r--r-- 1 su su 18763 Сен 9 13:26 report.xml -rw-r--r-- 1 root root 21573 Сен 9 13:26 2304020058671131785-1315560283.info -rw-r--r-- 1 root root 10326 Сен 9 13:26 2304020058671131785-1315560283.script -rw-r--r-- 1 su su 24352 Сен 9 13:26 3264330288285888354-1315560130.info -rw-r--r-- 1 su su 11507 Сен 9 13:26 3264330288285888354-1315560130.script drwx------ 30 su su 1464 Сен 9 13:25 ../ -rw-r--r-- 1 root root 315 Сен 9 13:25 2304020058671131785-1315560283_1315560315_root_.bashrc.diff -rwxr-xr-x 1 su root 7709 Сен 9 13:15 l3bashrc -rwxr-xr-x 1 su root 234 Сен 9 13:15 l3prompt |
$tail ../.bashrc
export GREP_OPTIONS="--color=auto" # Source global definitions if [ -r /etc/bashrc ]; then . /etc/bashrc fi #[ $0 == l3script ] && . /home/su/.lilalo/l3bashrc && _l3_start #. ${user_home}/.lilalo/l3bashrc && _l3_start . ~/.lilalo/l3bashrc && _l3_start |
$sudo vim ../../kos_aa/.bashrc
|
$l
итого 126 -rw-r--r-- 1 su su 7908 Сен 9 13:27 268158378436214913-1315560387.script drwx------ 30 su su 1464 Сен 9 13:27 ../ -rw-r--r-- 1 su su 849 Сен 9 13:27 268158378436214913-1315560387.info drwxr-xr-x 2 su root 576 Сен 9 13:26 ./ -rw-r--r-- 1 su su 194 Сен 9 13:26 .report.dat -rw-r--r-- 1 su su 18763 Сен 9 13:26 report.xml -rw-r--r-- 1 root root 21573 Сен 9 13:26 2304020058671131785-1315560283.info -rw-r--r-- 1 root root 10326 Сен 9 13:26 2304020058671131785-1315560283.script -rw-r--r-- 1 su su 24352 Сен 9 13:26 3264330288285888354-1315560130.info -rw-r--r-- 1 su su 11507 Сен 9 13:26 3264330288285888354-1315560130.script -rw-r--r-- 1 root root 315 Сен 9 13:25 2304020058671131785-1315560283_1315560315_root_.bashrc.diff -rwxr-xr-x 1 su root 7709 Сен 9 13:15 l3bashrc -rwxr-xr-x 1 su root 234 Сен 9 13:15 l3prompt |
$cd /tmp/
|
$wget http://xgu.ru/lilalo/lilalo.tar.gz
--2011-09-09 13:31:34-- http://xgu.ru/lilalo/lilalo.tar.gz Распознаётся xgu.ru... 91.205.16.235 Устанавливается соединение с xgu.ru|91.205.16.235|:80... соединение установлено. Запрос HTTP послан, ожидается ответ... 200 OK Длина: 151793 (148K) [application/x-gzip] Saving to: «lilalo.tar.gz» 100%[=============================================>] 151 793 270K/s в 0,5s 2011-09-09 13:31:35 (270 KB/s) - «lilalo.tar.gz» saved [151793/151793] |
$tar -xvf lilalo.tar.gz -z
lilalo/ lilalo/l3config.pm lilalo/lm-ssh lilalo/lm lilalo/tail-backend.pl lilalo/PM/ lilalo/PM/Text-Iconv-1.4.tar.gz lilalo/PM/Term-VT102-0.82.tar.gz lilalo/FILES lilalo/l3prompt ... lilalo/CVS/ lilalo/CVS/Repository lilalo/CVS/Root lilalo/CVS/Entries lilalo/l3-cgi lilalo/lilalo.kdi lilalo/HISTORY lilalo/LICENSE lilalo/l3-backend lilalo/l3-report |
$cd lilalo
|
$l
итого 428 drwxrwxrwt 13 root root 640 Сен 9 13:31 ../ drwxr-xr-x 8 su su 860 Мар 16 2008 ./ -rwxr-xr-x 1 su su 32757 Мар 16 2008 l3-agent drwxr-xr-x 2 su su 100 Мар 13 2008 CVS/ -rwxr-xr-x 1 su su 7522 Мар 13 2008 l3bashrc -rwxr-xr-x 1 su su 78084 Мар 13 2008 l3-frontend -rw-r--r-- 1 su su 5781 Мар 10 2008 l3config.pm -rwxr-xr-x 1 su su 5168 Мар 10 2008 install -rwxr-xr-x 1 su su 234 Мар 10 2008 l3prompt ... -rw-r--r-- 1 su su 1598 Ноя 3 2005 tail-all.pl -rwxr-xr-x 1 su su 47 Ноя 2 2005 l3-report -rwxr-xr-x 1 su su 31413 Ноя 2 2005 lm-report -rw-r--r-- 1 su su 4162 Окт 22 2005 lilalo.kdi drwxr-xr-x 3 su su 160 Май 22 2005 share/ -rw-r--r-- 1 su su 1496 Май 22 2005 FILES -rw-r--r-- 1 su su 452 Май 22 2005 INSTALL -rwxr-xr-x 1 su su 316 Май 22 2005 lm-ssh -rw-r--r-- 1 su su 157 Май 22 2005 taillast.pl -rw-r--r-- 1 su su 111 Май 22 2005 .tarball |
$l3
![]() l3 l3_close_session l3mass_upload l3script l3-agent l3-config l3pwd l3shot l3cd l3_fix_prompt l3_save_last_line l3upload |
$l3-agent
|
$l3-agent
l3-agent is already running: pid=12491; pidfile=/home/su/.lilalo/l3-agent.pid |
$cat /home/su/.bashrc
# .bashrc # User specific aliases and functions export GREP_OPTIONS="--color=auto" # Source global definitions if [ -r /etc/bashrc ]; then . /etc/bashrc fi #[ $0 == l3script ] && . /home/su/.lilalo/l3bashrc && _l3_start #. ${user_home}/.lilalo/l3bashrc && _l3_start . ~/.lilalo/l3bashrc && _l3_start |
$l3 pwd
/users/su/mrg/mrgar.mrg.com/su |
$l
итого 428 drwxrwxrwt 13 root root 640 Сен 9 14:06 ../ drwxr-xr-x 8 su su 860 Мар 16 2008 ./ -rwxr-xr-x 1 su su 32757 Мар 16 2008 l3-agent drwxr-xr-x 2 su su 100 Мар 13 2008 CVS/ -rwxr-xr-x 1 su su 7522 Мар 13 2008 l3bashrc -rwxr-xr-x 1 su su 78084 Мар 13 2008 l3-frontend -rw-r--r-- 1 su su 5781 Мар 10 2008 l3config.pm -rwxr-xr-x 1 su su 5168 Мар 10 2008 install -rwxr-xr-x 1 su su 234 Мар 10 2008 l3prompt ... -rw-r--r-- 1 su su 1598 Ноя 3 2005 tail-all.pl -rwxr-xr-x 1 su su 47 Ноя 2 2005 l3-report -rwxr-xr-x 1 su su 31413 Ноя 2 2005 lm-report -rw-r--r-- 1 su su 4162 Окт 22 2005 lilalo.kdi drwxr-xr-x 3 su su 160 Май 22 2005 share/ -rw-r--r-- 1 su su 1496 Май 22 2005 FILES -rw-r--r-- 1 su su 452 Май 22 2005 INSTALL -rwxr-xr-x 1 su su 316 Май 22 2005 lm-ssh -rw-r--r-- 1 su su 157 Май 22 2005 taillast.pl -rw-r--r-- 1 su su 111 Май 22 2005 .tarball |
$cat l3
![]() l3-agent l3-cgi l3config.pm l3prompt l3-upload l3-backend l3-cgi-lite l3files/ l3-report l3bashrc l3-config l3-frontend l3scripts |
$cd
![]() CVS/ l3-cgi l3-upload README DELETE/ l3-cgi-lite LICENSE rebuild-all-logs doc/ l3-config lilalo.kdi share/ FILES l3config.pm lm tail-all.pl HISTORY .#l3config.pm.1.15 .#lm.1.14 tail-backend.pl install l3files/ lm-install taillast.pl INSTALL l3-frontend lm-report .tarball l3-agent .#l3-frontend.1.26 lm-ssh TODO .#l3-agent.1.21 l3prompt mysql l3-backend l3-report nohup.out l3bashrc l3scripts PM/ |
$l /etc/init.d/l
![]() linbilling-timer local lvm2-monitor |
$l3
![]() l3 l3_close_session l3mass_upload l3script l3-agent l3-config l3pwd l3shot l3cd l3_fix_prompt l3_save_last_line l3upload |
$cp l3-backend /usr/bin/
cp: невозможно создать обычный файл `/usr/bin/l3-backend': Отказано в доступе |
$vim install
|
$cat ../install
#!/bin/sh hostname=`hostname` uname -a | grep -qi freebsd || hostname=`hostname -f` ############################################################################### # # Set this variables before installation: lilalo_user=${lilalo_user:-su} lab=${lab:-mrg} install_l3bashrc_for_this_users=${users:-"root su kos_aa"} # users who will use l3agent and l3script lilalo_context="/users/${lilalo_user}/${lab}/${hostname}" ... step "Downloading l3prompt" ${wget} ${url_l3prompt} step "Downloading l3-agent" '${wget} ${url_l3agent}; ${wget} ${url_l3config_pm}; ${wget} ${url_l3config}' step "Downloading perl modules for l3-agent" '{ for i in ${perl_modules}; do ${wget} ${url_perl_modules}/$i.tar.gz; done; }' step "Installing perl modules for l3-agent" '{ for i in ${perl_modules}; do tar xvfz $i.tar.gz; cd $i*[^z]; perl Makefile.PL; make; make install; cd ..; done; }' step "Installing l3bashrc to users home directories" install_to_users_homes $install_l3bashrc_for_this_users step "Adding l3bashrc invocation to ~/.bashrc " install_to_users_bashrc $install_l3bashrc_for_this_users step "Adding l3-agent invocation to ~/.bash_profile " install_to_users_bash_profile $install_l3bashrc_for_this_users cd / rm -rf ${temp_dir} show_final_message |
$cat /etc/li
![]() libao.conf lilalo/ lilo.conf.old linbilling.cfg libaudit.conf lilo.conf lilo.conf.save linbilling_rule.cfg |
$cat /etc/lilalo/
![]() cat: /etc/lilalo/: Это каталог |
$cat /etc/lilalo/l3config.pm
package l3config; use utf8; use Exporter; use vars qw(@ISA @EXPORT $VERSION); use Getopt::Long; @ISA = ('Exporter'); @EXPORT = qw(%Config &init_config); our $System_Config_File = "/etc/lilalo.conf"; our $User_Config_File = "$ENV{HOME}/.l3rc"; $ENV{HOME} ||= "/tmp"; ... my %argv_config; my %file_config; read_config_file(\%file_config, $System_Config_File); read_config_file(\%file_config, $User_Config_File); GetOptions(\%argv_config, map "$_=s", keys %Config); %Config = (%Config, %file_config, %argv_config); for my $key (keys %Config) { utf8::decode($Config{$key}); } } |
$l
итого 428 drwxrwxrwt 13 root root 640 Сен 9 14:14 ../ drwxr-xr-x 8 su su 860 Сен 9 14:12 ./ -rwxr-xr-x 1 su su 32757 Мар 16 2008 l3-agent drwxr-xr-x 2 su su 100 Мар 13 2008 CVS/ -rwxr-xr-x 1 su su 7522 Мар 13 2008 l3bashrc -rwxr-xr-x 1 su su 78084 Мар 13 2008 l3-frontend -rw-r--r-- 1 su su 5781 Мар 10 2008 l3config.pm -rwxr-xr-x 1 su su 5168 Мар 10 2008 install -rwxr-xr-x 1 su su 234 Мар 10 2008 l3prompt ... -rw-r--r-- 1 su su 1598 Ноя 3 2005 tail-all.pl -rwxr-xr-x 1 su su 47 Ноя 2 2005 l3-report -rwxr-xr-x 1 su su 31413 Ноя 2 2005 lm-report -rw-r--r-- 1 su su 4162 Окт 22 2005 lilalo.kdi drwxr-xr-x 3 su su 160 Май 22 2005 share/ -rw-r--r-- 1 su su 1496 Май 22 2005 FILES -rw-r--r-- 1 su su 452 Май 22 2005 INSTALL -rwxr-xr-x 1 su su 316 Май 22 2005 lm-ssh -rw-r--r-- 1 su su 157 Май 22 2005 taillast.pl -rw-r--r-- 1 su su 111 Май 22 2005 .tarball |
$cat l3
![]() l3-agent l3-cgi l3config.pm l3prompt l3-upload l3-backend l3-cgi-lite l3files/ l3-report l3bashrc l3-config l3-frontend l3scripts |
$cat l3-frontend
#!/usr/bin/perl -w use POSIX qw(strftime); use lib '/etc/lilalo'; use l3config; use utf8; our @Command_Lines; our @Command_Lines_Index; our %Commands_Description; our %Args_Description; our %Sessions; ... $result .= "($section)" if $section; } else { 1 while ($result =~ s/(\s+)-(\s+)/$1+$2/sg); $result =~ s/\s+\(/(/; chomp $result; } } return $result; } |
$./l3
![]() l3-agent l3bashrc l3-cgi-lite l3files/ l3prompt l3-upload l3-backend l3-cgi l3-config l3-frontend l3-report |
$./l3-frontend
![]() Can't open /home/igor/mywi/mywi.txt for reading at ./l3-frontend line 2046. |
$vim l3-frontend
|
$cat l3
![]() l3-agent l3-cgi l3config.pm l3prompt l3-upload l3-backend l3-cgi-lite l3files/ l3-report l3bashrc l3-config l3-frontend l3scripts |
$cat l3-config
#!/usr/bin/perl use strict; use lib '/etc/lilalo/'; use l3config; print $Config{$ARGV[0]}."\n"; |
$vim l3-frontend
|
$cd /home/su/.lilalo/
|
$l
итого 402 -rw-r--r-- 1 su su 148385 Сен 9 14:18 268158378436214913-1315560387.script -rw-r--r-- 1 su su 2413 Сен 9 14:18 268158378436214913-1315560387.info -rw-r--r-- 1 su su 202 Сен 9 14:18 .report.dat -rw-r--r-- 1 su su 153725 Сен 9 14:18 report.xml drwxr-xr-x 2 su root 864 Сен 9 14:18 ./ drwx------ 30 su su 1464 Сен 9 14:18 ../ -rw-r--r-- 1 su su 0 Сен 9 14:18 268158378436214913-1315560387_1315563340_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Сен 9 14:15 268158378436214913-1315560387_1315563309_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Сен 9 14:12 268158378436214913-1315560387_1315563126_tmp_lilalo_install.diff -rw-r--r-- 1 su su 5 Сен 9 13:31 l3-agent.pid -rw-r--r-- 1 root root 21573 Сен 9 13:26 2304020058671131785-1315560283.info -rw-r--r-- 1 root root 10326 Сен 9 13:26 2304020058671131785-1315560283.script -rw-r--r-- 1 su su 24352 Сен 9 13:26 3264330288285888354-1315560130.info -rw-r--r-- 1 su su 11507 Сен 9 13:26 3264330288285888354-1315560130.script -rw-r--r-- 1 root root 315 Сен 9 13:25 2304020058671131785-1315560283_1315560315_root_.bashrc.diff -rwxr-xr-x 1 su root 7709 Сен 9 13:15 l3bashrc -rwxr-xr-x 1 su root 234 Сен 9 13:15 l3prompt |
$cat l3-agent.pid
|
$cat l3-agent.pid
|
$cat 268158378436214913-1315560387.scrip
![]() cat: 268158378436214913-1315560387.scrip: Нет такого файла или каталога |
$cat 268158378436214913-1315560387.script
Скрипт запущен Птн 09 Сен 2011 13:26:27 |
$1;2801;0c1;2801;0c
bash: 1: команда не найдена bash: 2801: команда не найдена bash: 0c1: команда не найдена bash: 2801: команда не найдена bash: 0c: команда не найдена |
$l3-
![]() l3-agent l3-backend l3-config |
$l3-agent --help
Unknown option: help l3-agent is already running: pid=12491; pidfile=/home/su/.lilalo/l3-agent.pid |
$l3-config
|
$l3-config --hrlp
|
$l3-config --help
|
$ps fax
PID TTY STAT TIME COMMAND 2 ? S< 0:00 [kthreadd] 3 ? S< 0:00 \_ [migration/0] 4 ? S< 0:01 \_ [ksoftirqd/0] 5 ? S< 0:00 \_ [watchdog/0] 6 ? S< 0:00 \_ [migration/1] 7 ? S< 0:05 \_ [ksoftirqd/1] 8 ? S< 0:00 \_ [watchdog/1] 9 ? S< 0:00 \_ [migration/2] 10 ? S< 0:05 \_ [ksoftirqd/2] ... 28267 ? S 0:00 \_ (ntlm_auth) --helper-protocol=squid-2.5-ntlmssp 28268 ? S 0:00 \_ (ntlm_auth) --helper-protocol=squid-2.5-ntlmssp 28269 ? S 0:00 \_ (ntlm_auth) --helper-protocol=squid-2.5-ntlmssp 28270 ? S 0:00 \_ (ntlm_auth) --helper-protocol=squid-2.5-ntlmssp 28271 ? S 0:00 \_ (ntlm_auth) --helper-protocol=squid-2.5-ntlmssp 28272 ? S 0:00 \_ (ntlm_auth) --helper-protocol=squid-2.5-ntlmssp 28273 ? S 0:00 \_ (ntlm_auth) --helper-protocol=squid-2.5-ntlmssp 22409 ? SNl 1:37 /opt/openfire/jre/bin/java -server -DopenfireHome=/opt/openf 18607 ? SNs 7:49 /sbin/syslogd -u syslogd -j /var/resolv 12491 ? Ss 5:23 l3-agent |
$ps fax | grep l3
22747 pts/1 S+ 0:00 \_ grep l3 12491 ? Ss 5:24 l3-agent |
$whic hl3-agent
![]() bash: whic: команда не найдена |
$which l3-agent
/usr/local/bin/l3-agent |
$cat /usr/local/bin/l3-agent
#!/usr/bin/perl -w # # (c) Igor Chubin, igor@chub.in, 2004-2008 # use strict; use POSIX; use Term::VT102; use Text::Iconv; use Time::Local 'timelocal_nocheck'; use IO::Socket; ... send_cache() && unlink($Config{cache}); } sleep($Config{"daemon_sleep_interval"} || 1); } unlink $Config{agent_pidfile}; } } sub init_variables { } |
$sudo grep 129 /config/firewall/useracl
#iptables -A useracl -s 10.10.120.129 -d nnm-club.ru -j ULOG --ulog-prefix "Kosarev NNM " #iptables -A useracl -s 10.10.120.129 -d nnm-club.ru -j ACCEPT #mail aent Kosarev iptables -A useracl -s 10.10.120.129 -d nnm-club.ru -j ULOG --ulog-prefix "Kosarev NNM " iptables -A useracl -s 10.10.120.129 -d nnm-club.ru -j ACCEPT #Kosarev NNM iptables -A useracl -p tcp -s 10.10.120.129 -d u69073.ftp.masterhost.ru -j ULOG --ulog-prefix "Masterhost " iptables -A useracl -p tcp -s 10.10.120.129 -d u69073.ftp.masterhost.ru -j ACCEPT #Masterhost iptables -A useracl -p tcp -s 10.10.120.129 -d nichost.ru -j ULOG --ulog-prefix "NIC FTP " iptables -A useracl -p tcp -s 10.10.120.129 -d nichost.ru -j ACCEPT #NIC FTP iptables -A useracl -p tcp -s 10.10.120.129 -d s14.h.mchost.ru -j ULOG --ulog-prefix "MCHOST FTP " iptables -A useracl -p tcp -s 10.10.120.129 -d s14.h.mchost.ru -j ACCEPT #MCHOST FTP iptables -A useracl -p tcp -s 10.10.120.129 -d 0/0 --dport 20:21 -j ULOG --ulog-prefix "Kosarev FTP " iptables -A useracl -p tcp -s 10.10.120.129 -d 0/0 --dport 20:21 -j ACCEPT #Kosarev FTP iptables -A useracl -p tcp -s 10.10.120.129 -d 0/0 --dport 2041:2042 -j ULOG --ulog-prefix "Kosarev MRIM " iptables -A useracl -p tcp -s 10.10.120.129 -d 0/0 --dport 2041:2042 -j ACCEPT #Kosarev MRIM iptables -A useracl -p tcp -s 10.10.120.129 -d 90.156.201.0/24 --dport 80 -j ULOG --ulog-prefix "Kosarev WWW " iptables -A useracl -p tcp -s 10.10.120.129 -d 90.156.201.17 --dport 80 -j ACCEPT #Kosarev WWW iptables -A useracl -p tcp -s 10.10.120.129 -d 90.156.201.23 --dport 80 -j ACCEPT #Kosarev WWW iptables -A useracl -p tcp -s 10.10.120.129 -d 90.156.201.40 --dport 80 -j ACCEPT #Kosarev WWW iptables -A useracl -p tcp -s 10.10.120.129 -d 90.156.201.41 --dport 80 -j ACCEPT #Kosarev WWW |
$iptables -L -v | grep 120.129
bash: iptables: команда не найдена |
$sudo iptables -L -v -n | grep 120.129
0 0 ULOG all -- * * 10.10.120.129 193.107.211.4 ULOG copy_range 0 nlgroup 1 prefix `Kosarev NNM ' queue_threshold 1 0 0 ACCEPT all -- * * 10.10.120.129 193.107.211.4 309 195K ULOG tcp -- * * 10.10.120.129 90.156.199.78 ULOG copy_range 0 nlgroup 1 prefix `Masterhost ' queue_threshold 1 309 195K ACCEPT tcp -- * * 10.10.120.129 90.156.199.78 0 0 ULOG tcp -- * * 10.10.120.129 194.85.61.54 ULOG copy_range 0 nlgroup 1 prefix `NIC FTP ' queue_threshold 1 0 0 ACCEPT tcp -- * * 10.10.120.129 194.85.61.54 0 0 ULOG tcp -- * * 10.10.120.129 178.208.83.18 ULOG copy_range 0 nlgroup 1 prefix `MCHOST FTP ' queue_threshold 1 0 0 ACCEPT tcp -- * * 10.10.120.129 178.208.83.18 37 1981 ULOG tcp -- * * 10.10.120.129 0.0.0.0/0 tcp dpts:20:21 ULOG copy_range 0 nlgroup 1 prefix `Kosarev FTP ' queue_threshold 1 37 1981 ACCEPT tcp -- * * 10.10.120.129 0.0.0.0/0 tcp dpts:20:21 997 69004 ULOG tcp -- * * 10.10.120.129 0.0.0.0/0 tcp dpts:2041:2042 ULOG copy_range 0 nlgroup 1 prefix `Kosarev MRIM ' queue_threshold 1 997 69004 ACCEPT tcp -- * * 10.10.120.129 0.0.0.0/0 tcp dpts:2041:2042 0 0 ULOG tcp -- * * 10.10.120.129 90.156.201.0/24 tcp dpt:80 ULOG copy_range 0 nlgroup 1 prefix `Kosarev WWW ' queue_threshold 1 0 0 ACCEPT tcp -- * * 10.10.120.129 90.156.201.17 tcp dpt:80 0 0 ACCEPT tcp -- * * 10.10.120.129 90.156.201.23 tcp dpt:80 0 0 ACCEPT tcp -- * * 10.10.120.129 90.156.201.40 tcp dpt:80 0 0 ACCEPT tcp -- * * 10.10.120.129 90.156.201.41 tcp dpt:80 |
$sudo su
|
#l
total 8029 drwxr-xr-x 2 su root 976 Sep 12 07:56 ./ -rw-r--r-- 1 su su 204 Sep 12 07:56 .report.dat -rw-r--r-- 1 root root 456 Sep 12 07:56 10350288104344998-1315799787.info -rw-r--r-- 1 root root 253 Sep 12 07:56 10350288104344998-1315799787.script -rw-r--r-- 1 su su 7858786 Sep 12 07:56 268158378436214913-1315560387.script -rw-r--r-- 1 su su 237601 Sep 9 14:33 report.xml -rw-r--r-- 1 su su 3859 Sep 9 14:33 268158378436214913-1315560387.info drwx------ 30 su su 1464 Sep 9 14:18 ../ -rw-r--r-- 1 su su 0 Sep 9 14:18 268158378436214913-1315560387_1315563340_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Sep 9 14:15 268158378436214913-1315560387_1315563309_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Sep 9 14:12 268158378436214913-1315560387_1315563126_tmp_lilalo_install.diff -rw-r--r-- 1 su su 5 Sep 9 13:31 l3-agent.pid -rw-r--r-- 1 root root 21573 Sep 9 13:26 2304020058671131785-1315560283.info -rw-r--r-- 1 root root 10326 Sep 9 13:26 2304020058671131785-1315560283.script -rw-r--r-- 1 su su 24352 Sep 9 13:26 3264330288285888354-1315560130.info -rw-r--r-- 1 su su 11507 Sep 9 13:26 3264330288285888354-1315560130.script -rw-r--r-- 1 root root 315 Sep 9 13:25 2304020058671131785-1315560283_1315560315_root_.bashrc.diff -rwxr-xr-x 1 su root 7709 Sep 9 13:15 l3bashrc -rwxr-xr-x 1 su root 234 Sep 9 13:15 l3prompt |
#cd /home/kos_aa/.l
![]() .l3rc .lftp/ .lilalo/ .lpoptions |
#cd /home/kos_aa/.lilalo/
|
#l
total 8029 drwxr-xr-x 2 su root 976 Sep 12 07:56 ./ -rw-r--r-- 1 su su 204 Sep 12 07:56 .report.dat -rw-r--r-- 1 root root 456 Sep 12 07:56 10350288104344998-1315799787.info -rw-r--r-- 1 root root 253 Sep 12 07:56 10350288104344998-1315799787.script -rw-r--r-- 1 su su 7858786 Sep 12 07:56 268158378436214913-1315560387.script -rw-r--r-- 1 su su 237601 Sep 9 14:33 report.xml -rw-r--r-- 1 su su 3859 Sep 9 14:33 268158378436214913-1315560387.info drwx------ 30 su su 1464 Sep 9 14:18 ../ -rw-r--r-- 1 su su 0 Sep 9 14:18 268158378436214913-1315560387_1315563340_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Sep 9 14:15 268158378436214913-1315560387_1315563309_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Sep 9 14:12 268158378436214913-1315560387_1315563126_tmp_lilalo_install.diff -rw-r--r-- 1 su su 5 Sep 9 13:31 l3-agent.pid -rw-r--r-- 1 root root 21573 Sep 9 13:26 2304020058671131785-1315560283.info -rw-r--r-- 1 root root 10326 Sep 9 13:26 2304020058671131785-1315560283.script -rw-r--r-- 1 su su 24352 Sep 9 13:26 3264330288285888354-1315560130.info -rw-r--r-- 1 su su 11507 Sep 9 13:26 3264330288285888354-1315560130.script -rw-r--r-- 1 root root 315 Sep 9 13:25 2304020058671131785-1315560283_1315560315_root_.bashrc.diff -rwxr-xr-x 1 su root 7709 Sep 9 13:15 l3bashrc -rwxr-xr-x 1 su root 234 Sep 9 13:15 l3prompt |
#cd /home/kos_aa/.l
![]() .l3rc .lftp/ .lilalo/ .lpoptions |
#cd /home/kos_aa/.lilalo/
|
#l
total 13 drwx------ 12 kos_aa kos_aa 568 Sep 9 13:27 ../ -rw-r--r-- 1 kos_aa root 7709 Sep 9 13:15 l3bashrc -rwxr-xr-x 1 kos_aa root 234 Sep 9 13:15 l3prompt drwxr-xr-x 2 kos_aa root 96 Sep 9 11:00 ./ |
#cd
|
#l
total 13 drwx------ 12 kos_aa kos_aa 568 Sep 9 13:27 ../ -rw-r--r-- 1 kos_aa root 7709 Sep 9 13:15 l3bashrc -rwxr-xr-x 1 kos_aa root 234 Sep 9 13:15 l3prompt drwxr-xr-x 2 kos_aa root 96 Sep 9 11:00 ./ |
#cd
|
#exit
|
$sudo su
|
#l
total 8134 drwxr-xr-x 2 su root 1088 Sep 12 09:33 ./ -rw-r--r-- 1 root root 444 Sep 12 09:33 2566179733199511555-1315805639.info -rw-r--r-- 1 root root 253 Sep 12 09:33 2566179733199511555-1315805639.script -rw-r--r-- 1 su su 7862170 Sep 12 09:33 268158378436214913-1315560387.script -rw-r--r-- 1 su su 267 Sep 12 09:33 .report.dat -rw-r--r-- 1 root root 21360 Sep 12 07:56 10350288104344998-1315799787.info -rw-r--r-- 1 root root 3212 Sep 12 07:56 10350288104344998-1315799787.script -rw-r--r-- 1 su su 3912 Sep 12 07:56 268158378436214913-1315560387.info -rw-r--r-- 1 su su 248231 Sep 12 07:56 report.xml ... -rw-r--r-- 1 su su 0 Sep 9 14:15 268158378436214913-1315560387_1315563309_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Sep 9 14:12 268158378436214913-1315560387_1315563126_tmp_lilalo_install.diff -rw-r--r-- 1 su su 5 Sep 9 13:31 l3-agent.pid -rw-r--r-- 1 root root 21573 Sep 9 13:26 2304020058671131785-1315560283.info -rw-r--r-- 1 root root 10326 Sep 9 13:26 2304020058671131785-1315560283.script -rw-r--r-- 1 su su 24352 Sep 9 13:26 3264330288285888354-1315560130.info -rw-r--r-- 1 su su 11507 Sep 9 13:26 3264330288285888354-1315560130.script -rw-r--r-- 1 root root 315 Sep 9 13:25 2304020058671131785-1315560283_1315560315_root_.bashrc.diff -rwxr-xr-x 1 su root 7709 Sep 9 13:15 l3bashrc -rwxr-xr-x 1 su root 234 Sep 9 13:15 l3prompt |
#cd /usr/local/sbin/
|
#l
total 8134 drwxr-xr-x 2 su root 1088 Sep 12 09:33 ./ -rw-r--r-- 1 root root 444 Sep 12 09:33 2566179733199511555-1315805639.info -rw-r--r-- 1 root root 253 Sep 12 09:33 2566179733199511555-1315805639.script -rw-r--r-- 1 su su 7862170 Sep 12 09:33 268158378436214913-1315560387.script -rw-r--r-- 1 su su 267 Sep 12 09:33 .report.dat -rw-r--r-- 1 root root 21360 Sep 12 07:56 10350288104344998-1315799787.info -rw-r--r-- 1 root root 3212 Sep 12 07:56 10350288104344998-1315799787.script -rw-r--r-- 1 su su 3912 Sep 12 07:56 268158378436214913-1315560387.info -rw-r--r-- 1 su su 248231 Sep 12 07:56 report.xml ... -rw-r--r-- 1 su su 0 Sep 9 14:15 268158378436214913-1315560387_1315563309_tmp_lilalo_l3-frontend.diff -rw-r--r-- 1 su su 0 Sep 9 14:12 268158378436214913-1315560387_1315563126_tmp_lilalo_install.diff -rw-r--r-- 1 su su 5 Sep 9 13:31 l3-agent.pid -rw-r--r-- 1 root root 21573 Sep 9 13:26 2304020058671131785-1315560283.info -rw-r--r-- 1 root root 10326 Sep 9 13:26 2304020058671131785-1315560283.script -rw-r--r-- 1 su su 24352 Sep 9 13:26 3264330288285888354-1315560130.info -rw-r--r-- 1 su su 11507 Sep 9 13:26 3264330288285888354-1315560130.script -rw-r--r-- 1 root root 315 Sep 9 13:25 2304020058671131785-1315560283_1315560315_root_.bashrc.diff -rwxr-xr-x 1 su root 7709 Sep 9 13:15 l3bashrc -rwxr-xr-x 1 su root 234 Sep 9 13:15 l3prompt |
#cd /usr/local/sbin/
|
#l
![]() total 703 drwxr-xr-x 16 root root 384 Sep 7 16:51 ../ drwxr-xr-x 4 su root 2696 Jul 18 16:07 ./ -rwxr-xr-x 1 root root 4701 Jul 18 16:07 AutoCreateWhite_List -rwxr-xr-x 1 root root 268 Jun 8 09:08 Check_Squiddaemon -rwxr-xr-x 1 root root 265 Jun 8 09:05 Check_Samsdaemon -rwx------ 1 root root 672 Jun 8 09:04 Spamheaders -rwxr-xr-x 1 su root 2248 Jun 8 09:04 ShutdownUrodov -rwxr-xr-x 1 root root 1840 Jun 8 09:04 NUlog -rwx------ 1 root root 1240 Jun 8 09:03 MaxSize ... -rwx------ 1 root root 71 Mar 4 2010 CGP_logs -rwx------ 1 root root 760 Mar 4 2010 Fired_Users -rwx------ 1 root root 795 Mar 4 2010 MailFromSiteMrgarant.ru -rw------- 1 root root 748 Mar 4 2010 ParseExcel -rwx------ 1 root root 159 Mar 4 2010 Sa-learn -rwxr-xr-x 1 root root 6188 Mar 4 2010 faxanswer -rwxr-xr-x 1 root root 6300 Mar 4 2010 faxconfig -rwxr-xr-x 1 root root 6144 Mar 4 2010 faxdeluser -rwx------ 1 root root 46247 Mar 6 2004 xcode -rw-rw-r-- 1 root root 222 Mar 6 2004 xcodeln.pl |
#l
total 703 drwxr-xr-x 16 root root 384 Sep 7 16:51 ../ drwxr-xr-x 4 su root 2696 Jul 18 16:07 ./ -rwxr-xr-x 1 root root 4701 Jul 18 16:07 AutoCreateWhite_List -rwxr-xr-x 1 root root 268 Jun 8 09:08 Check_Squiddaemon -rwxr-xr-x 1 root root 265 Jun 8 09:05 Check_Samsdaemon -rwx------ 1 root root 672 Jun 8 09:04 Spamheaders -rwxr-xr-x 1 su root 2248 Jun 8 09:04 ShutdownUrodov -rwxr-xr-x 1 root root 1840 Jun 8 09:04 NUlog -rwx------ 1 root root 1240 Jun 8 09:03 MaxSize ... -rwx------ 1 root root 71 Mar 4 2010 CGP_logs -rwx------ 1 root root 760 Mar 4 2010 Fired_Users -rwx------ 1 root root 795 Mar 4 2010 MailFromSiteMrgarant.ru -rw------- 1 root root 748 Mar 4 2010 ParseExcel -rwx------ 1 root root 159 Mar 4 2010 Sa-learn -rwxr-xr-x 1 root root 6188 Mar 4 2010 faxanswer -rwxr-xr-x 1 root root 6300 Mar 4 2010 faxconfig -rwxr-xr-x 1 root root 6144 Mar 4 2010 faxdeluser -rwx------ 1 root root 46247 Mar 6 2004 xcode -rw-rw-r-- 1 root root 222 Mar 6 2004 xcodeln.pl |
#!/bin/sh hostname=`hostname` uname -a | grep -qi freebsd || hostname=`hostname -f` ############################################################################### # # Set this variables before installation: lilalo_user=${lilalo_user:-su} lab=${lab:-mrg} install_l3bashrc_for_this_users=${users:-"root su kos_aa"} # users who will use l3agent and l3script lilalo_context="/users/${lilalo_user}/${lab}/${hostname}" # ############################################################################### lilalo_rc=.l3rc lilalo_home=.lilalo url_lilalo="http://xgu.ru/lilalo" url_l3bashrc="${url_lilalo}"/l3bashrc url_l3agent="${url_lilalo}"/l3-agent url_l3config_pm="${url_lilalo}"/l3config.pm url_l3config="${url_lilalo}"/l3-config url_l3prompt="${url_lilalo}"/l3prompt url_perl_modules=${url_lilalo}/ perl_modules="Term-VT102 Text-Iconv" apt_get_install_this="perl make libmodule-build-perl libc6-dev gcc" wget=wget uname -a | grep -qi bsd && wget=fetch normC='\033[0;39m' whiteC='\033[1;37m' redC='\033[0;31m' greenC='\033[0;32m' apt_get_install_deps() { return 0 if which apt-get >& /dev/null then apt-get install -y $apt_get_install_this else echo "Please install this dependencies manually:" echo $apt_get_install_this echo "Have you installed this already (y/n)?" echo y | read answer if echo $answer | grep -q ^[yY] then true else echo Please install the dependencies and rerun the script exit 1 fi fi } step() { msg="$1" shift printf "${whiteC}""$msg""...${normC}\n" # eval "$@" 2>&1 | sed 's/^/|\ \ \ /' && printf "Ok\n" || printf "Failed\n" eval "$@" 2>&1 > log 2>&1 && \ { cat log | sed 's/^/|\ \ \ /' printf "${greenC}""Ok\n""${normC}" } || \ { cat log | sed 's/^/|\ \ \ /' printf "${redC}""Failed\n""${normC}" } } get_user_home() { uname -a | grep -qi freebsd && pw user show "$@"| awk -F: '{print $9}' || getent passwd "$@"| awk -F: '{print $6}' } install_to_users_homes() { . l3bashrc users="$@" set -x for user in $users do user_home=`get_user_home "$user"` mkdir -p ${user_home}/${lilalo_home} mkdir /etc/lilalo/ cp l3config.pm /etc/lilalo/ cp l3-agent /usr/local/bin cp l3-config /usr/local/bin ln -s `which bash` /usr/local/bin/l3script chmod 755 /usr/local/bin/l3-{agent,config} cp l3bashrc ${user_home}/${lilalo_home} cp l3prompt ${user_home}/${lilalo_home} chmod 755 ${user_home}/${lilalo_home}/l3prompt chown -R $user ${user_home}/${lilalo_home} echo l3cd=${lilalo_context}/$user > ${user_home}/${lilalo_rc} chown -R $user ${user_home}/${lilalo_rc} done set +x } install_to_users_bashrc() { users="$@" for user in $users do user_home=`get_user_home "$user"` grep -q lilalo ${user_home}/.bashrc 2> /dev/null\ || echo "[ \$0 == l3script ] && . ${user_home}/.lilalo/l3bashrc && _l3_start" >> ${user_home}/.bashrc; chown -R ${user} ${user_home}/.bashrc done } install_to_users_bash_profile() { users="$@" for user in $users do user_home=`get_user_home "$user"` grep -q l3-agent ${user_home}/.bash_profile 2> /dev/null \ || { echo >> ${user_home}/.bash_profile ; cat ${user_home}/.bash_profile | sed '1s/^/l3-agentX/' | tr X '\n' > /tmp/$$$$l3 ; mv /tmp/$$$$l3 ${user_home}/.bash_profile; chown -R ${user} ${user_home}/.bash_profile; } done } show_usage() { cat <<USAGE Usage: $0 USAGE } show_final_message() { cat <<FINAL_MESSAGE Installation is successfully completed. Now restart your shell or relogin to start script writing. Your current lilalo context is ${lilalo_context}/USER If you use xgu.ru backend, your labs will be available at http://xgu.ru/l3/${lilalo_context} Use commands $ l3cd ${lilalo_context%/*/*}/MY-NEW-CONTEXT/${hostname}/USER $ l3pwd to change and to know your current context. For further information see http://xgu.ru/lilalo/ (in Russian). Thank you gor using LiLaLo. Happy Labbing! (don't forget to restart bash or relogin) FINAL_MESSAGE } temp_dir=/tmp/lilalo-install-temp-$$ mkdir -p ${temp_dir} cd ${temp_dir} step "Installing dependencies" apt_get_install_deps step "Downloading l3bashrc" ${wget} ${url_l3bashrc} step "Downloading l3prompt" ${wget} ${url_l3prompt} step "Downloading l3-agent" '${wget} ${url_l3agent}; ${wget} ${url_l3config_pm}; ${wget} ${url_l3config}' step "Downloading perl modules for l3-agent" '{ for i in ${perl_modules}; do ${wget} ${url_perl_modules}/$i.tar.gz; done; }' step "Installing perl modules for l3-agent" '{ for i in ${perl_modules}; do tar xvfz $i.tar.gz; cd $i*[^z]; perl Makefile.PL; make; make install; cd ..; done; }' step "Installing l3bashrc to users home directories" install_to_users_homes $install_l3bashrc_for_this_users step "Adding l3bashrc invocation to ~/.bashrc " install_to_users_bashrc $install_l3bashrc_for_this_users step "Adding l3-agent invocation to ~/.bash_profile " install_to_users_bash_profile $install_l3bashrc_for_this_users cd / rm -rf ${temp_dir} show_final_message
# .bashrc # User specific aliases and functions alias cp='cp -i' alias mv='mv -i' alias rm='rm -i' alias d='ls' alias s='cd ..' alias p='cd -' # Read /etc/inputrc if the variable is not defined. [ -n "$INPUTRC" ] || export INPUTRC=/etc/inputrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi PATH=/root/bin:/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin ENV=$HOME/.bashrc USERNAME="root" export USERNAME ENV PATH #[ $0 == l3script ] && . /root/.lilalo/l3bashrc && _l3_start . ${user_home}/.lilalo/l3bashrc && _l3_start
libao.conf lilalo/ lilo.conf.old linbilling.cfg libaudit.conf lilo.conf lilo.conf.save linbilling_rule.cfg
package l3config; use utf8; use Exporter; use vars qw(@ISA @EXPORT $VERSION); use Getopt::Long; @ISA = ('Exporter'); @EXPORT = qw(%Config &init_config); our $System_Config_File = "/etc/lilalo.conf"; our $User_Config_File = "$ENV{HOME}/.l3rc"; $ENV{HOME} ||= "/tmp"; our %Config = ( "skip_empty" => "yes", "skip_interrupted" => "no", "skip_wrong" => "no", "editors" => ["vi", "pico", "ee", "vim", "nano"], "pagers" => ["more", "less", "zmore", "zless", "info", "man", "mc", "trafshow", "screen", "cfdisk", "trafshow-bsd", "yes", "lynx", "links", "centericq" ], "full_output_commands" => ["cat"], "terminal" => ["mc"], "suppress_editors" => "yes", "suppress_pagers" => "yes", "suppress_terminal" => "yes", "terminal_width" => 400, "terminal_height" => 1000, "verbose" => "yes", "head_lines" => 10, "tail_lines" => 10, "cache_head_lines" => 2500, "cache_tail_lines" => 2500, "skip_text" => "...", "show_time" => "yes", "show_diffs" => "yes", "show_screenshots" => "yes", "show_comments" => "yes", "show_notes" => "yes", "input" => "$ENV{HOME}/.lilalo", "diffs" => "", "input_mask" => "*.script", "encoding" => "utf-8", "cache" => "$ENV{HOME}/.lilalo/report.xml", "cache_stat" => "$ENV{HOME}/.lilalo/.report.dat", "output" => "/tmp/report.html", "output_mask" => "INDEX", "output_format" => "html", "cgi_path" => "/l3", "frontend_files" => "/l3files", "frontend_css" => "/l3files/l3.css", "l3shot_path" => "/l3shot/", "l3shot_suffix" => ".png", "frontend_google_ico" => "/l3/google.ico", "frontend_linux_ico" => "/l3/linux.ico", "frontend_freebsd_ico" => "/l3/freebsd.ico", "frontend_opennet_ico" => "/l3/opennet.ico", "frontend_local_ico" => "/l3/freebsd.ico", "mywi_server" => "127.0.0.1", "mywi_port" => "19801", "stat_inactivity_interval" => "1800", "signature" => "#lm:", "from" => "", "to" => "", "lab" => "", "keywords" => "linux command", "files_keywords" => "linux file", comment_width => "300", note_width => "500", time_width => "6em", "mode" => "daemon", # daemon | normal "daemon_sleep_interval" => "10", "detach" => "yes", "agent_pidfile" => "$ENV{HOME}/.lilalo/l3-agent.pid", "backend_address" => "xgu.ru", "backend_port" => "18030", "backend_pidfile" => "/tmp/l3-backend.pid", "backend_datafile" => "/var/lilalo/lablogs-xml/backend.xml", "backend_datadir" => "/var/lilalo/lablogs-xml/", "upload_dir" => "/var/www/l3shot", "l3-agent" => "l3-agent", "l3-backend" => "l3-backend", "course-name" => "", "course-code" => "", "course-date" => "", "course-center" => "", "course-trainer" => "", "course-student" => "", "filter" => "", #lm "show_host" => "no", "l3cd" => "", # ТекÑÑий конÑекÑÑ Ð¿ÐµÑÐµÑ Ð²Ð°ÑеннÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´ # ÐозможнÑе ваÑианÑÑ: # ÐУРС/ÐÐТÐ-ÐÐЧÐÐ # ÐÐТÐ-ÐÐЧÐÐ # УÐÐÐÐÐÐÐÐТÐÐ 3-report" => "./lm-report", "l3-report" => "./l3-report", # ÐаÑалоги "path_lilalo" => "/var/lilalo/", "path_classes" => "/var/lilalo/classes/", "path_lablogs" => "/var/lilalo/lablogs/", "courses_path" => "/var/lilalo/courses/", "outpath" => "/var/lilalo/out/", "path_web" => "/var/www/l3", # ÐÑÑÑ Ðº web-оÑÑÑÑам "path_share" => "./share/", # ÐÑÑÑ Ðº web-оÑÑÑÑам # Ð¤Ð°Ð¹Ð»Ñ "runfile" => "lm.run", "logfile" => "lm.log", "class" => "class", # ÐÐ¼Ñ Ñайла клаÑÑа "class_suffix" => ".xml", # CÑÑÑÐ¸ÐºÑ Ñайла клаÑÑа "classfile" => "", "sshkey" => "$ENV{HOME}/.ssh/id_dsa.pub", "lmssh" => "./lm-ssh", "lminstall" => "./lm-install", "ssh_user" => "root", "l3scripts" => "l3scripts", "cgi_path_info" => "", "cgi2file" => "", "year" => "2006", "commands_to_show_at_a_go" => "100", "start_from_command" => "0", ); sub read_config_file { my $config = $_[0]; my $filename = $_[1]; open(CONFIG, "$filename") or return; while (<CONFIG>) { chomp; s/#.*//; next if /^\s*$/; my ($var, $val) = split /\s*=\s*/, $_, 2; $var =~ s/\s*//; $config->{$var} = $val; } close(CONFIG); } sub init_config { my %argv_config; my %file_config; read_config_file(\%file_config, $System_Config_File); read_config_file(\%file_config, $User_Config_File); GetOptions(\%argv_config, map "$_=s", keys %Config); %Config = (%Config, %file_config, %argv_config); for my $key (keys %Config) { utf8::decode($Config{$key}); } }
# .bashrc # User specific aliases and functions export GREP_OPTIONS="--color=auto" # Source global definitions if [ -r /etc/bashrc ]; then . /etc/bashrc fi #[ $0 == l3script ] && . /home/su/.lilalo/l3bashrc && _l3_start #. ${user_home}/.lilalo/l3bashrc && _l3_start . ~/.lilalo/l3bashrc && _l3_start
#!/usr/bin/perl -w # # (c) Igor Chubin, igor@chub.in, 2004-2008 # use strict; use POSIX; use Term::VT102; use Text::Iconv; use Time::Local 'timelocal_nocheck'; use IO::Socket; use lib "/etc/lilalo"; use l3config; our @Command_Lines; our @Command_Lines_Index; our %Diffs; our %Sessions; our %Script_Files; # Информация о позициях в скрипт-файлах, # до которых уже выполнен разбор # и информация о времени модификации файла # $Script_Files{$file}->{size} # $Script_Files{$file}->{tell} our $Killed =0; # В режиме демона -- процесс получил сигнал о завершении sub init_variables; sub main; sub load_diff_files; sub bind_diff; sub extract_commands_from_cline; sub load_command_lines; sub sort_command_lines; sub print_command_lines; sub printq; sub save_cache_stat; sub load_cache_stat; sub print_session; sub load_diff_files { my @pathes = @_; for my $path (@pathes) { my $template = "*.diff"; my @files = <$path/$template>; my $i=0; for my $file (@files) { next if defined($Diffs{$file}); my %diff; # Старый формат имени diff-файла # DEPRECATED if ($file=~m@/(D?[0-9][0-9]?[0-9]?)[^/]*?([0-9]*):([0-9]*):?([0-9]*)@) { $diff{"day"}=$1 || ""; $diff{"hour"}=$2; $diff{"min"}=$3; $diff{"sec"}=$4 || 0; $diff{"uid"} = 0 if $path =~ m@/root/@; print "diff loaded: $diff{day} $diff{hour}:$diff{min}:$diff{sec}\n"; } # Новый формат имени diff-файла elsif ($file =~ m@.*/([^_]*)_([0-9]+)(.*)@) { $diff{"local_session_id"} = $1; $diff{"time"} = $2; $diff{"filename"} = $3; $diff{"filename"} =~ s@_@/@g; $diff{"filename"} =~ s@//@_@g; print "diff loaded: $diff{filename} (time=$diff{time},session=$diff{local_session_id})\n"; } else { next; } # Чтение и изменение кодировки содержимого diff-файла local $/; open (F, "$file") or return "Can't open file $file ($_[0]) for reading"; my $text = <F>; if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i) { my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8"); $text = $converter->convert($text); } close(F); $diff{"text"}=$text; $diff{"path"}=$path; $diff{"bind_to"}=""; $diff{"time_range"}=-1; $diff{"index"}=$i; $Diffs{$file} = \%diff; $i++; } } } sub bind_diff { print "Trying to bind diff...\n"; my $cl = shift; my $hour = $cl->{"hour"}; my $min = $cl->{"min"}; my $sec = $cl->{"sec"}; my $min_dt = 10000; if (defined($cl->{"diff"})) { print STDERR "Command ".$cl->{time}." is already bound"; return; } # Загружаем новые diff-файлы # Это нужно делать непосредственно перед привязкой, поскольку diff'ы могли образоваться только что for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) { load_diff_files($lab_log); } my $diff_to_bind; for my $diff_key (keys %Diffs) { my $diff = $Diffs{$diff_key}; next if ($diff->{"local_session_id"} && $cl->{"local_session_id"} && ($cl->{"local_session_id"} ne $diff->{"local_session_id"})); next if ($diff->{"day"} && $cl->{"day"} && ($cl->{"day"} ne $diff->{"day"})); my $dt; if (not $diff->{"time"}) { print STDERR "diff time is 0"; print STDERR join(" ", keys(%$diff)); print STDERR $diff->{text}; } if (not $cl->{"time"}) { print STDERR "cl time is 0"; } if ($diff->{"time"} && $cl->{"time"}) { $dt = $diff->{"time"} - $cl->{"time"} } else { $dt=($diff->{"hour"}-$hour)*3600 +($diff->{"min"}-$min)*60 + ($diff->{"sec"}-$sec); } if ($dt >=0 && $dt < $min_dt && !$diff->{"bind_to"}) { $min_dt = $dt; $diff_to_bind = $diff_key; } } if ($diff_to_bind) { print "Approppriate diff found: dt=$min_dt\n"; $Diffs{$diff_to_bind}->{"bind_to"}=$cl; $cl->{"diff"} = $diff_to_bind; } else { print STDERR "Diff not found\n"; print STDERR "cl{time}",$cl->{time},"\n"; } } sub extract_commands_from_cline # Разобрать командную строку $_[1] и возвратить хэш, содержащий # номер первого появление команды в строке: # команда => первая позиция { my $cline = $_[0]; my @lists = split /\;/, $cline; my @commands = (); for my $list (@lists) { push @commands, split /\|/, $list; } my %commands; my %files; my $i=0; for my $command (@commands) { $command =~ /\s*(\S+)\s*(.*)/; if ($1 && $1 eq "sudo" ) { $commands{"$1"}=$i++; $command =~ s/\s*sudo\s+//; } $command =~ /\s*(\S+)\s*(.*)/; if ($1 && !defined $commands{"$1"}) { $commands{"$1"}=$i++; }; } return %commands; } sub load_command_lines { my $lab_scripts_path = $_[0]; my $lab_scripts_mask = $_[1]; my $cline_re_base = qq' ( (?:\\^?([0-9]*C?)) # exitcode (?:_([0-9]+)_)? # uid (?:_([0-9]+)_) # pid (...?) # day (.?.?) # lab \\s # space separator ([0-9][0-9]):([0-9][0-9]):([0-9][0-9]) # time .\\[50D.\\[K # killing symbols (.*?([\$\#]\\s?)) # prompt (.*) # command line ) '; my $cline_re = qr/$cline_re_base/sx; my $cline_re2 = qr/$cline_re_base$/sx; my $cline_re_v2_base = qq' ( v2[\#] # version ([0-9]+)[\#] # history line number ([0-9]+)[\#] # exitcode ([0-9]+)[\#] # uid ([0-9]+)[\#] # pid ([0-9]+)[\#] # time (.*?)[\#] # pwd .\\[1024D.\\[K # killing symbols (.*?([\$\#]\\s?)) # prompt (.*) # command line ) '; my $cline_re_v2 = qr/$cline_re_v2_base/sx; my $cline_re2_v2 = qr/$cline_re_v2_base$/sx; my $cline_re_v3_base = qq' ( v3[\#] # version .* ) '; my $cline_re_v3 = qr/$cline_re_v3_base/sx; my $cline_re2_v3_base = qq' ( v3[\#] # version ([0-9]+)[\#] # history line number ([0-9]+)[\#] # exitcode ([0-9]+)[\#] # uid ([0-9]+)[\#] # pid ([0-9]+)[\#] # time (.*?)[\#] # pwd (.*?)[\#] # nonce (.*?([\$\#]\\s?)) # prompt (.*) # command line ) '; my $cline_re2_v3 = qr/$cline_re2_v3_base$/sx; my %vt; # Хэш виртуальных терминалов. По одному на каждый сеанс my $cline_vt = Term::VT102->new ( 'cols' => $Config{"terminal_width"}, 'rows' => $Config{"terminal_height"}); my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8") if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i); print "Parsing lab scripts...\n" if $Config{"verbose"} =~ /y/; my $file; my $skip_info; my $commandlines_loaded =0; my $commandlines_processed =0; my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>; for $file (@lab_scripts){ # Пропускаем файл, если он не изменялся со времени нашего предудущего прохода my $size = (stat($file))[7]; next if ($Script_Files{$file} && $Script_Files{$file}->{size} && $Script_Files{$file}->{size} >= $size); my $local_session_id; # Начальное значение идентификатора текущего сеанса определяем из имени скрипта # Впоследствии оно может быть уточнено $file =~ m@.*/([^/]*)\.script$@; $local_session_id = $1; if (not defined($vt{$local_session_id})) { $vt{$local_session_id} = Term::VT102->new ( 'cols' => $Config{"terminal_width"}, 'rows' => $Config{"terminal_height"}); } #Если файл только что появился, #пытаемся найти и загрузить информацию о соответствующей ему сессии if (!$Script_Files{$file}) { my $session_file = $file; $session_file =~ s/\.script/.info/; if (open(SESSION, $session_file)) { local $/; my $data = <SESSION>; close(SESSION); for my $session_data ($data =~ m@<session>(.*?)</session>@sg) { my %session; while ($session_data =~ m@<([^>]*?)>(.*?)</\1>@sg) { $session{$1} = $2; } $local_session_id = $session{"local_session_id"} if $session{"local_session_id"}; $Sessions{$local_session_id}=\%session; } #Загруженную информацию сразу же отправляем в поток print_session($Config{cache}, $local_session_id); } else { die "can't open session file"; } } open (FILE, "$file"); binmode FILE; # Переходим к тому месту, где мы окончили разбор seek (FILE, $Script_Files{$file}->{tell}, 0) if $Script_Files{$file}->{tell}; $Script_Files{$file}->{size} = $size; $Script_Files{$file}->{tell} = 0 unless $Script_Files{$file}->{tell}; $file =~ m@.*/(.*?)-.*@; print "\n+- processing file $file\n| " if $Config{"verbose"} =~/y/; my $tty = $1; my %cl; my $last_output_length=0; my $saved_output; while (<FILE>) { $commandlines_processed++; next if s/^Script started on.*?\n//s; if (/[0-9][0-9]:[0-9][0-9]:[0-9][0-9].\[[0-9][0-9]D.\[K/ && m/$cline_re/) { s/.*\x0d(?!\x0a)//; m/$cline_re2/gs; $commandlines_loaded++; $last_output_length=0; # Previous command my %last_cl = %cl; my $this_line = $1; my $err = $2 || ""; $cl{"local_session_id"} = $local_session_id; # Parse new command $cl{"uid"} = $3; #$cl{"euid"} = $cl{"uid"}; # Если в команде обнаружится sudo, euid поменяем на 0 $cl{"pid"} = $4; $cl{"day"} = $5; $cl{"lab"} = $6; $cl{"hour"} = $7; $cl{"min"} = $8; $cl{"sec"} = $9; #$cl{"fullprompt"} = $10; $cl{"prompt"} = $11; $cl{"raw_cline"} = $12; { use bytes; $cl{"raw_start"} = tell (FILE) - length($this_line); $cl{"raw_output_start"} = tell FILE; } $cl{"raw_file"} = $file; $cl{"err"} = 0; $cl{"output"} = ""; $cl{"tty"} = $tty; $cline_vt->process($cl{"raw_cline"}."\n"); $cl{"cline"} = $cline_vt->row_plaintext (1); $cl{"cline"} =~ s/\s*$//; $cl{"cline"} =~ s/.*?[\#\$]\s*//; $cline_vt->reset(); my %commands = extract_commands_from_cline($cl{"cline"}); #$cl{"euid"}=0 if defined $commands{"sudo"}; my @comms = sort { $commands{$a} cmp $commands{$b} } keys %commands; $cl{"last_command"} = $comms[$#comms] || ""; if ( $Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $cl{"last_command"}, @{$Config{"editors"}}) || $Config{"suppress_pagers"} =~ /^y/i && grep ($_ eq $cl{"last_command"}, @{$Config{"pagers"}}) || $Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $cl{"last_command"}, @{$Config{"terminal"}}) ) { $cl{"suppress_output"} = "1"; } else { $cl{"suppress_output"} = "0"; } $skip_info = 0; print " ",$cl{"last_command"}; if (grep ($_ eq $last_cl{"last_command"}, @{$Config{"editors"}})) { bind_diff(\%last_cl); } # Error code $last_cl{"raw_end"} = $cl{"raw_start"}; $last_cl{"err"}=$err; $last_cl{"err"}=130 if $err eq "^C"; # Output if (!$last_cl{"suppress_output"} || $last_cl{"err"}) { for (my $i=0; $i<$Config{"terminal_height"}; $i++) { my $line= $vt{$local_session_id}->row_plaintext($i); next if !defined ($line) ; #|| $line =~ /^\s*$/; $line =~ s/\s*$//; $line .= "\n" unless $line =~ /^\s*$/; $last_cl{"output"} .= $line; } } else { $last_cl{"output"}= ""; } $vt{$local_session_id}->reset(); # Save if (!$Config{"lab"} || $cl{"lab"} eq $Config{"lab"}) { # Changing encoding for (keys %last_cl) { next if /raw/; $last_cl{$_} = $converter->convert($last_cl{$_}) if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i); } push @Command_Lines, \%last_cl; # Сохранение позиции в файле, до которой выполнен # успешный разбор $Script_Files{$file}->{tell} = $last_cl{raw_end}; } next; } elsif (m/$cline_re_v2/ || m/$cline_re_v3/) { # Разбираем командную строку версии 2 my $before=$_; s/.*\x0d(?!\x0a)//; my $re; if (m/$cline_re_v2/) { $re=$cline_re2_v2; } else { s/.\[1K.\[10D//gs; $re=$cline_re2_v3; print STDERR "... $_ ...\n"; } m/$re/gs; $commandlines_loaded++; $last_output_length=0; # Previous command my %last_cl = %cl; $cl{"local_session_id"} = $local_session_id; # Parse new command my $this_line = $1; $cl{"history"} = $2; my $err = $3; $cl{"uid"} = $4; #$cl{"euid"} = $cl{"uid"}; # Если в команде обнаружится sudo, euid поменяем на 0 $cl{"pid"} = $5; $cl{"time"} = $6; $cl{"pwd"} = $7; $cl{"nonce"} = $8; #$cl{"fullprompt"} = $8; $cl{"prompt"} = $10; #$cl{"raw_cline"}= $10; $cl{"raw_cline"}= $before; { use bytes; $cl{"raw_start"} = tell (FILE) - length($before); $cl{"raw_output_start"} = tell FILE; } $cl{"raw_file"} = $file; $cl{"err"} = 0; $cl{"output"} = ""; #$cl{"tty"} = $tty; $cline_vt->process($cl{"raw_cline"}."\n"); $cl{"cline"} = $cline_vt->row_plaintext (1); $cl{"cline"} =~ s/\s*$//; $cl{"cline"} =~ s/.*?[\#\$]\s*//; $cline_vt->reset(); print STDERR "cline=".$cl{"cline"}."<<\n"; my %commands = extract_commands_from_cline($cl{"cline"}); #$cl{"euid"} = 0 if defined $commands{"sudo"}; my @comms = sort { $commands{$a} cmp $commands{$b} } keys %commands; $cl{"last_command"} = $comms[$#comms] || ""; print STDERR "last_command=".$cl{"last_command"}."<<\n"; if ( $Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $cl{"last_command"}, @{$Config{"editors"}}) || $Config{"suppress_pagers"} =~ /^y/i && grep ($_ eq $cl{"last_command"}, @{$Config{"pagers"}}) || $Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $cl{"last_command"}, @{$Config{"terminal"}}) ) { $cl{"suppress_output"} = "1"; } else { $cl{"suppress_output"} = "0"; } $skip_info = 0; if ($Config{verbose} =~ /y/i) { print "\n| " if $commandlines_loaded % 5 == 1; print " ",$cl{"last_command"}; } if (defined($last_cl{time}) && grep ($_ eq $last_cl{"last_command"}, @{$Config{"editors"}})) { bind_diff(\%last_cl); } # Error code $last_cl{"err"}=$err; $last_cl{"raw_end"} = $cl{"raw_start"}; # Output if (!$last_cl{"suppress_output"} || $last_cl{"err"}) { $last_cl{"output"}=$saved_output; for (my $i=0; $i<$Config{"terminal_height"}; $i++) { my $line= $vt{$local_session_id}->row_plaintext($i); next if !defined ($line) ; #|| $line =~ /^\s*$/; $line =~ s/\s*$//; $line .= "\n" unless $line =~ /^\s*$/; $last_cl{"output"} .= $line; } } else { $last_cl{"output"}= ""; } $vt{$local_session_id}->reset(); $saved_output=""; # Changing encoding for (keys %last_cl) { next if /raw/; if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i) { $last_cl{$_} = $converter->convert($last_cl{$_}) } } if (defined($last_cl{time})) { print STDERR "push id=".$last_cl{time}."\n"; push @Command_Lines, \%last_cl; # Сохранение позиции в файле, до которой выполнен # успешный разбор $Script_Files{$file}->{tell} = $last_cl{raw_end}; } next; } if (($commandlines_processed%100) == 0) { # Каждые сто строк обнуляем терминал и переносим вывод из него в кэш # Output for (my $i=0; $i<$Config{"terminal_height"}; $i++) { my $line= $vt{$local_session_id}->row_plaintext($i); next if !defined ($line) ; #|| $line =~ /^\s*$/; $line =~ s/\s*$//; $line .= "\n" unless $line =~ /^\s*$/; $saved_output .= $line; } $vt{$local_session_id}->reset(); $last_output_length=0; } # Иначе, это строка вывода $last_output_length+=length($_); #if (!$cl{"suppress_output"} || $last_output_length < 5000) { if ($last_output_length < 50000) { $vt{$local_session_id}->process("$_"."\n") } else { if (!$skip_info && defined($cl{last_command})) { print "($cl{last_command})"; $skip_info = 1; } } } close(FILE); } if ($Config{"verbose"} =~ /y/) { print "\n`- finished.\n" ; print "Lines loaded: $commandlines_processed\n"; print "Command lines: $commandlines_loaded\n"; } } sub sort_command_lines { print "Sorting command lines..." if $Config{"verbose"} =~ /y/; # Sort Command_Lines # Write Command_Lines to Command_Lines_Index my @index; for (my $i=0;$i<=$#Command_Lines;$i++) { $index[$i]=$i; } @Command_Lines_Index = sort { defined($Command_Lines[$index[$a]]->{"time"}) && defined($Command_Lines[$index[$b]]->{"time"}) ? $Command_Lines[$index[$a]]->{"time"} <=> $Command_Lines[$index[$b]]->{"time"} : defined($Command_Lines[$index[$a]]->{"day"}) && defined($Command_Lines[$index[$b]]->{"day"}) && defined($Command_Lines[$index[$a]]->{"hour"}) && defined($Command_Lines[$index[$b]]->{"hour"}) && defined($Command_Lines[$index[$a]]->{"min"}) && defined($Command_Lines[$index[$b]]->{"min"}) && defined($Command_Lines[$index[$a]]->{"sec"}) && defined($Command_Lines[$index[$b]]->{"sec"}) ? $Command_Lines[$index[$a]]->{"day"} cmp $Command_Lines[$index[$b]]->{"day"} || $Command_Lines[$index[$a]]->{"hour"} <=> $Command_Lines[$index[$b]]->{"hour"} || $Command_Lines[$index[$a]]->{"min"} <=> $Command_Lines[$index[$b]]->{"min"} || $Command_Lines[$index[$a]]->{"sec"} <=> $Command_Lines[$index[$b]]->{"sec"} : 0 } @index; print "finished\n" if $Config{"verbose"} =~ /y/; } sub printq { my $TO = shift; my $text = join "", @_; $text =~ s/&/&/g; $text =~ s/</</g; $text =~ s/>/>/g; print $TO $text; } =cut Вывести результат обработки журнала. =cut sub print_command_lines { my $output_filename=$_[0]; open(OUT, ">>", $output_filename) or die "Can't open $output_filename for writing\n"; my $cl; my $in_range=0; for my $i (@Command_Lines_Index) { $cl = $Command_Lines[$i]; if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { $in_range=1; next; } if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) { $in_range=0; next; } next if ($Config{"from"} && $Config{"to"} && !$in_range) || ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) || ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); # Вырезаем из вывода только нужное количество строк my $output=""; if (!grep ($_ eq $cl->{"last_command"}, @{$Config{"full_output_commands"}}) && ($Config{"head_lines"} || $Config{"tail_lines"})) { # Partialy output my @lines = split '\n', $cl->{"output"}; # head my $mark=1; for (my $i=0; $i<= $#lines && $i < $Config{"cache_head_lines"}; $i++) { $output .= $lines[$i]."\n"; } # tail my $start=$#lines-$Config{"cache_tail_lines"}+1; if ($start < 0) { $start=0; $mark=0; } if ($start < $Config{"cache_head_lines"}) { $start=$Config{"cache_head_lines"}; $mark=0; } $output .= $Config{"skip_text"}."\n" if $mark; for ($i=$start; $i<= $#lines; $i++) { $output .= $lines[$i]."\n"; } } else { # Full output $output .= $cl->{"output"}; } # Совместимость с labmaker # Переводим в секунды Эпохи # В labmaker'е данные хранились в неудобной форме: hour, min, sec, day of year # Информация о годе отсутствовала # Её можно внести: # Декабрь 2004 год; остальные -- 2005 год. my $year = 2005; #$year = 2004 if ( $cl->{day} > 330 ); $year = $Config{year} if $Config{year}; # timelocal( $sec, $min, $hour, $mday,$mon,$year); $cl->{time} ||= timelocal_nocheck($cl->{sec},$cl->{min},$cl->{hour},$cl->{day},0,$year); # Начинаем вывод команды print OUT "<command>\n"; print OUT "<l3cd>$Config{l3cd}</l3cd>\n" if $Config{"l3cd"}; for my $element (qw( local_session_id history uid pid time pwd raw_start raw_output_start raw_end raw_file tty err last_command history nonce )) { next unless defined($cl->{"$element"}); print OUT "<$element>".$cl->{$element}."</$element>\n"; } for my $element (qw( prompt cline )) { next unless defined($cl->{"$element"}); print OUT "<$element>"; printq(\*OUT,$cl->{"$element"}); print OUT "</$element>\n"; } #note #note_title print OUT "<output>"; printq(\*OUT,$output); print OUT "</output>\n"; if ($cl->{"diff"}) { print OUT "<diff>"; printq(\*OUT,${$Diffs{$cl->{"diff"}}}{"text"}); print OUT "</diff>\n"; } print OUT "</command>\n"; } close(OUT); } sub print_session { my $output_filename = $_[0]; my $local_session_id = $_[1]; return if not defined($Sessions{$local_session_id}); print "printing session info. session id = ".$local_session_id."\n" if $Config{verbose} =~ /y/; open(OUT, ">>", $output_filename) or die "Can't open $output_filename for writing\n"; print OUT "<session>\n"; print OUT "<l3cd>$Config{l3cd}</l3cd>\n" if $Config{"l3cd"}; my %session = %{$Sessions{$local_session_id}}; for my $key (keys %session) { print OUT "<$key>".$session{$key}."</$key>\n"; print " ".$key,"\n"; } print OUT "</session>\n"; close(OUT); } sub send_cache { # Если в кэше что-то накопилось, # попытаемся отправить это на сервер # my $cache_was_sent=0; if (open(CACHE, $Config{cache})) { local $/; my $cache = <CACHE>; close(CACHE); my $socket = IO::Socket::INET->new( PeerAddr => $Config{backend_address}, PeerPort => $Config{backend_port}, proto => "tcp", Type => SOCK_STREAM ); if ($socket) { print $socket $cache; close($socket); $cache_was_sent = 1; } } return $cache_was_sent; } sub save_cache_stat { open (CACHE, ">$Config{cache_stat}"); for my $f (keys %Script_Files) { print CACHE "$f\t",$Script_Files{$f}->{size},"\t",$Script_Files{$f}->{tell},"\n"; } close(CACHE); } sub load_cache_stat { if (open (CACHE, "$Config{cache_stat}")) { while(<CACHE>) { chomp; my ($f, $size, $tell) = split /\t/; $Script_Files{$f}->{size} = $size; $Script_Files{$f}->{tell} = $tell; } close(CACHE); }; } main(); sub process_was_killed { $Killed = 1; } sub reload { init_config; } sub main { $| = 1; init_variables(); init_config(); if ($Config{"mode"} ne "daemon") { # В нормальном режиме работы нужно # считать скрипты, обработать их и записать # результат выполнения в результирующий файл. # После этого завершить работу. # Очистим кэш-файл, если он существовал if (open (CACHE, ">", $Config{"cache"})) { close(CACHE); }; load_command_lines($Config{"input"}, $Config{"input_mask"}); sort_command_lines; #process_command_lines; print_command_lines($Config{"cache"}); } else { if (open(PIDFILE, $Config{agent_pidfile})) { my $pid = <PIDFILE>; close(PIDFILE); if ($^O eq 'linux' && $pid &&(! -e "/proc/$pid" || !`grep $Config{"l3-agent"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`)) { print "Removing stale pidfile\n"; unlink $Config{agent_pidfile} or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!"; } elsif ($^O eq 'freebsd' && defined($pid) && $pid ne "" && not `ps axo uid,pid,command | grep '$< $pid $Config{"l3-agent"}' | grep -v grep 2> /dev/null`) { print "Removing stale pidfile\n"; unlink $Config{agent_pidfile} or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!"; } elsif ($^O eq 'linux' || $^O eq 'freebsd' ) { print "l3-agent is already running: pid=$pid; pidfile=$Config{agent_pidfile}\n"; exit(0); } else { print "Unknown operating system"; exit(0); } } if ($Config{detach} =~ /^y/i) { #$Config{verbose} = "no"; my $pid = fork; exit if $pid; die "Couldn't fork: $!" unless defined ($pid); open(PIDFILE, ">", $Config{agent_pidfile}) or die "Can't open pidfile ". $Config{agent_pidfile}. " for wrting: $!"; print PIDFILE $$; close(PIDFILE); for my $handle (*STDIN, *STDOUT, *STDERR) { open ($handle, "+<", "/dev/null") or die "can't reopen $handle to /dev/null: $!" } POSIX::setsid() or die "Can't start a new session: $!"; $0 = $Config{"l3-agent"}; $SIG{INT} = $SIG{TERM} = \&process_was_killed; $SIG{HUP} = \&reload; } while (not $Killed) { @Command_Lines = (); @Command_Lines_Index = (); load_cache_stat(); load_command_lines($Config{"input"}, $Config{"input_mask"}); if (@Command_Lines) { sort_command_lines; #process_command_lines; print_command_lines($Config{"cache"}); } save_cache_stat(); if (-e $Config{cache} && (stat($Config{cache}))[7]) { send_cache() && unlink($Config{cache}); } sleep($Config{"daemon_sleep_interval"} || 1); } unlink $Config{agent_pidfile}; } } sub init_variables { }
Скрипт запущен Птн 09 Сен 2011 13:26:27
l3-agent l3-cgi l3config.pm l3prompt l3-upload l3-backend l3-cgi-lite l3files/ l3-report l3bashrc l3-config l3-frontend l3scripts
#!/usr/bin/perl use strict; use lib '/etc/lilalo/'; use l3config; use IO::Socket; use POSIX qw(:sys_wait_h); sub main; main(); sub REAPER { 1 until (-1 == waitpid(-1, WNOHANG)); $SIG{CHLD} = \&REAPER; } sub process_was_killed { # Здесь должна быть красивая процедура # завершения демона unlink $Config{backend_pidfile}; exit(0); } sub main { init_config(); # Проверяем, возможно демон уже запущен # Если он работает, просто завершаемся if (open(PIDFILE, $Config{backend_pidfile})) { my $pid = <PIDFILE>; close(PIDFILE); if ( ! -e "/proc/$pid" || !`grep $Config{"l3-backend"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`) { print "Removing stale pidfile\n"; unlink $Config{backend_pidfile} or die "Can't remove stale pidfile ". $Config{backend_pidfile}. " : $!"; } else { print "l3-backend is already running\n"; exit(0); } } # Уходим в background, если необходимо if ($Config{detach} =~ /^y/i) { #$Config{verbose} = "no"; my $pid = fork; exit if $pid; die "Couldn't fork: $!" unless defined ($pid); open(PIDFILE, ">", $Config{backend_pidfile}) or die "Can't open pidfile ". $Config{backend_pidfile}. " for wrting: $!"; print PIDFILE $$; close(PIDFILE); for my $handle (*STDIN, *STDOUT, *STDERR) { open ($handle, "+<", "/dev/null") or die "can't reopen $handle to /dev/null: $!" } POSIX::setsid() or die "Can't start a new session: $!"; $0 = $Config{"l3-backend"}; $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&process_was_killed; } # Открываем сетевой сокет и слушаем my $server = IO::Socket::INET->new( LocalPort => $Config{backend_port}, Type => SOCK_STREAM, Reuse => 1, Listen => 10 ); if (!$server) { die "Couldn't bind to socket ".$Config{backend_port}."\n"; } $SIG{CHLD} = 'IGNORE'; # При получении новых соединенений, # порождаем дочерние процессы while (my $client = $server->accept()) { my $pid; next if $pid = fork; die "fork: $!" unless defined $pid; # Это наш ответвлённый клиент close($server); my $saved_data = ""; # Считываем данные и передаём их в точку получения open(OUT, ">>", $Config{"backend_datafile"}); select OUT; $|=1; while(<$client>) { print OUT $_; $saved_data .= $_; } close(OUT); #open(LOG, ">>", "/tmp/l3-backend.log"); #print LOG "Saved data:$saved_data\n"; #close(LOG); while ($saved_data =~ m@<(session|command)>(.*)</\1>@sg) { #open(LOG, ">>", "/tmp/l3-backend.log"); #print LOG "Found element $1\n"; #close(LOG); my $element_name = $1; my $element = $2; if ($element =~ m@<l3cd>(.*?)</l3cd>@msg) { # Обнаружен элемент l3cd # Информация должна быть сохранена в соответствующий каталог my $l3cd = $1; # Путь l3cd должен быть не пуст, # и в нём могут быть только символы латинского алфавита, цифры и знаки _ и - if ($l3cd && $l3cd =~ /^[a-zA-Z_\/0-9-]*/) { system("mkdir -m 770 -p $Config{backend_datadir}/$l3cd"); if (open(OUT, ">>", $Config{"backend_datadir"}."/$l3cd/data.xml")) { print OUT "<$element_name>".$element."</$element_name>"; close(OUT); }; } } } } continue { # Наш родитель close ($client); } }
#!/usr/bin/perl use strict; use lib '/etc/lilalo/'; use l3config; print $Config{$ARGV[0]}."\n";
#!/usr/bin/perl -w use POSIX qw(strftime); use lib '/etc/lilalo'; use l3config; use utf8; our @Command_Lines; our @Command_Lines_Index; our %Commands_Description; our %Args_Description; our %Sessions; our $debug_output=""; # Используйте эту переменную, если нужно передать отладочную информацию our %filter; our $filter_url; sub init_filter; our %Files; # vvv Инициализация переменных выполняется процедурой init_variables our @Day_Name; our @Month_Name; our @Of_Month_Name; our %Search_Machines; our %Elements_Visibility; # ^^^ our $First_Command=$0; our $Last_Command=40; our %Stat; our %frequency_of_command; # Сколько раз в журнале встречается какая команда our $table_number=1; our %tigra_hints; my %mywi_cache_for; # Кэш для экономии обращений к mywi sub count_frequency_of_commands; sub make_comment; sub make_new_entries_table; sub load_command_lines_from_xml; sub load_sessions_from_xml; sub sort_command_lines; sub process_command_lines; sub init_variables; sub main; sub collapse_list($); sub minutes_passed; sub print_all_txt; sub print_all_html; sub print_edit_all_html; sub print_command_lines_html; sub print_command_lines_txt; sub print_files_html; sub print_stat_html; sub print_header_html; sub print_footer_html; sub tigra_hints_generate; #### mywi # sub mywi_init; sub load_mywitxt; sub mywi_process_query($); # sub add_to_log($$); sub parse_query; sub search_in_txt; sub add_to_log($$); sub mywi_guess($); # main(); sub main { $| = 1; init_variables(); init_config(); $Config{frontend_ico_path}=$Config{frontend_css}; $Config{frontend_ico_path}=~s@/[^/]*$@@; init_filter(); mywi_init(); load_command_lines_from_xml($Config{"backend_datafile"}); load_sessions_from_xml($Config{"backend_datafile"}); sort_command_lines; process_command_lines; if (defined($filter{action}) && $filter{action} eq "edit") { print_edit_all_html($Config{"output"}); } else { print_all_html($Config{"output"}); } } sub init_filter { if ($Config{filter}) { # Инициализация фильтра for (split /&/,$Config{filter}) { my ($var, $val) = split /=/; $filter{$var} = $val || ""; } } $filter_url = join ("&", map("$_=$filter{$_}", keys %filter)); } # extract_from_cline # In: $what = commands | args # Out: return ссылка на хэш, содержащий результаты разбора # команда => позиция # Разобрать командную строку $_[1] и возвратить хэш, содержащий # номер первого появление команды в строке: # команда => первая позиция sub extract_from_cline { my $what = $_[0]; my $cline = $_[1]; my @lists = split /\;/, $cline; my @command_lines = (); for my $command_list (@lists) { push(@command_lines, split(/\|/, $command_list)); } my %position_of_command; my %position_of_arg; my $i=0; for my $command_line (@command_lines) { $command_line =~ s@^\s*@@; $command_line =~ /\s*(\S+)\s*(.*)/; if ($1 && $1 eq "sudo" ) { $position_of_command{"$1"}=$i++; $command_line =~ s/\s*sudo\s+//; } if ($command_line !~ m@^\s*\S*/etc/@) { $command_line =~ s@^\s*\S+/@@; } $command_line =~ /\s*(\S+)\s*(.*)/; my $command = $1; my $args = $2; if ($command && !defined $position_of_command{"$command"}) { $position_of_command{"$command"}=$i++; }; if ($args) { my @args = split (/\s+/, $args); for my $a (@args) { $position_of_arg{"$a"}=$i++ if !defined $position_of_arg{"$a"}; }; } } if ($what eq "commands") { return \%position_of_command; } else { return \%position_of_arg; } } sub mywrap($) { return '<div class="t"><div class="b"><div class="l"><div class="r"><div class="bl"><div class="br"><div class="tl"><div class="tr">'.$_[0]. '</div></div></div></div></div></div></div></div>'; } sub tigra_hints_generate { my $tigra_hints_items=""; for my $hint_id (keys %tigra_hints) { $tigra_hints{$hint_id} =~ s@\n@<br/>@gs; $tigra_hints{$hint_id} =~ s@ - @ — @gs; $tigra_hints{$hint_id} =~ s@'@\\'@gs; # $tigra_hints_items .= "'$hint_id' : mywrap('".$tigra_hints{$hint_id}."'),"; $tigra_hints_items .= "'$hint_id' : '".mywrap($tigra_hints{$hint_id})."',"; } $tigra_hints_items =~ s/,$//; return <<TIGRA; var HINTS_CFG = { 'top' : 5, // a vertical offset of a hint from mouse pointer 'left' : 5, // a horizontal offset of a hint from mouse pointer 'css' : 'hintsClass', // a style class name for all hints, TD object 'show_delay' : 500, // a delay between object mouseover and hint appearing 'hide_delay' : 2000, // a delay between hint appearing and hint hiding 'wise' : true, 'follow' : true, 'z-index' : 0 // a z-index for all hint layers }, HINTS_CFG_NEW = { 'wise' : true, // don't go off screen, don't overlap the object in the document 'margin' : 10, // minimum allowed distance between the hint and the window edge (negative values accepted) 'gap' : 20, // minimum allowed distance between the hint and the origin (negative values accepted) 'align' : 'bctl', // align of the hint and the origin (by first letters origin's top|middle|bottom left|center|right to hint's top|middle|bottom left|center|right) 'css' : 'hintsClass', // a style class name for all hints, applied to DIV element (see style section in the header of the document) 'show_delay' : 0, // a delay between initiating event (mouseover for example) and hint appearing 'hide_delay' : 200, // a delay between closing event (mouseout for example) and hint disappearing 'follow' : true, // hint follows the mouse as it moves 'z-index' : 100, // a z-index for all hint layers 'IEfix' : false, // fix IE problem with windowed controls visible through hints (activate if select boxes are visible through the hints) 'IEtrans' : ['blendTrans(DURATION=.3)', null], // [show transition, hide transition] - nice transition effects, only work in IE5+ 'opacity' : 90 // opacity of the hint in %% }, HINTS_ITEMS = { $tigra_hints_items }; var myHint = new THints (HINTS_CFG, HINTS_ITEMS); function mywrap (s_) { return '<div class="t"><div class="b"><div class="l"><div class="r"><div class="bl"><div class="br"><div class="tl"><div class="tr">'+s_+ '</div></div></div></div></div></div></div></div>'; } TIGRA $a=<<TIGRA; TIGRA } sub count_frequency_of_commands { my $cline = $_[0]; my @commands = keys %{extract_from_cline("commands", $cline)}; for my $command (@commands) { $frequency_of_command{$command}++; } } sub make_comment { my $cline = $_[0]; #my $files = $_[1]; my @comments; my @commands = keys %{extract_from_cline("commands", $cline)}; my @args = keys %{extract_from_cline("args", $cline)}; return if (!@commands && !@args); #return "commands=".join(" ",@commands)."; files=".join(" ",@files); # Commands for my $command (@commands) { $command =~ s/'//g; #$frequency_of_command{$command}++; if (!$Commands_Description{$command}) { $mywi_cache_for{$command} ||= mywi_process_query($command) || ""; my $mywi = join ("\n", grep(/\([18]|sh|script\)/, split(/\n/, $mywi_cache_for{$command}))); $mywi =~ s/\s+/ /; if ($mywi !~ /^\s*$/) { $Commands_Description{$command} = $mywi; } else { next; } } push @comments, $Commands_Description{$command}; } return join(" \n", @comments); # Files for my $arg (@args) { $arg =~ s/'//g; if (!$Args_Description{$arg}) { my $mywi; $mywi = mywi_client ($arg); $mywi = join ("\n", grep(/\([5]\)/, split(/\n/, $mywi))); $mywi =~ s/\s+/ /; if ($mywi !~ /^\s*$/) { $Args_Description{$arg} = $mywi; } else { next; } } push @comments, $Args_Description{$arg}; } } =cut Процедура load_command_lines_from_xml выполняет загрузку разобранного lab-скрипта из XML-документа в переменную @Command_Lines # In: $datafile имя файла # Out: @CommandLines загруженные командные строки Предупреждение! Процедура не в состоянии обрабатывать XML-документ любой структуры. В действительности файл cache из которого загружаются данные просто напоминает XML с виду. =cut sub load_command_lines_from_xml { my $datafile = $_[0]; open (CLASS, $datafile) or die "Can't open file with xml lablog ",$datafile,"\n"; local $/; binmode CLASS, ":utf8"; $data = <CLASS>; close(CLASS); for $command ($data =~ m@<command>(.*?)</command>@sg) { my %cl; while ($command =~ m@<([^>]*?)>(.*?)</\1>@sg) { $cl{$1} = $2; } push @Command_Lines, \%cl; } } sub load_sessions_from_xml { my $datafile = $_[0]; open (CLASS, $datafile) or die "Can't open file with xml lablog ",$datafile,"\n"; local $/; binmode CLASS, ":utf8"; my $data = <CLASS>; close(CLASS); my $i=0; for my $session ($data =~ m@<session>(.*?)</session>@msg) { my %session_hash; while ($session =~ m@<([^>]*?)>(.*?)</\1>@sg) { $session_hash{$1} = $2; } $Sessions{$session_hash{local_session_id}} = \%session_hash; } } # sort_command_lines # In: @Command_Lines # Out: @Command_Lies_Index sub sort_command_lines { my @index; for (my $i=0;$i<=$#Command_Lines;$i++) { $index[$i]=$i; } @Command_Lines_Index = sort { $Command_Lines[$index[$a]]->{"time"} <=> $Command_Lines[$index[$b]]->{"time"} } @index; } ################## # process_command_lines # # Обрабатываются командные строки @Command_Lines # Для каждой строки определяется: # class класс # note комментарий # # In: @Command_Lines_Index # In-Out: @Command_Lines sub process_command_lines { my $current_command=0; my $prev_i; my $tab_seq =0 ; # номер команды в последовательности tab-completion # отличен от нуля только для тех последовательностей, # где постоянно нажимается клавиша tab COMMAND_LINE_PROCESSING: for my $i (@Command_Lines_Index) { $current_command++; next if $current_command < $Config{"start_from_command"}; last if $current_command > $Config{"start_from_command"} + $Config{"commands_to_show_at_a_go"}; my $cl = \$Command_Lines[$i]; # Запоминаем предыщуюу команду # Она нам потребуется, в частности, для ввода tab_seq рпи обработке tab_completion my $prev_cl; $prev_cl = \$Command_Lines[$prev_i] if defined($prev_i); $prev_i = $i; next if !$cl; for my $filter_key (keys %filter) { next COMMAND_LINE_PROCESSING if defined($$cl->{local_session_id}) && defined($Sessions{$$cl->{local_session_id}}->{$filter_key}) && $Sessions{$$cl->{local_session_id}}->{$filter_key} ne $filter{$filter_key}; } $$cl->{id} = $$cl->{"time"}; $$cl->{err} ||=0; # Класс команды $$cl->{"class"} = $$cl->{"err"} eq 130 ? "interrupted" : $$cl->{"err"} eq 127 ? "mistyped" : $$cl->{"err"} ? "wrong" : "normal"; if ($$cl->{"cline"} && $$cl->{"cline"} =~ /[^|`]\s*sudo/ || $$cl->{"uid"} eq 0) { $$cl->{"class"}.="_root"; } my $hint; count_frequency_of_commands($$cl->{"cline"}); $hint = make_comment($$cl->{"cline"}); if ($hint) { $$cl->{hint} = $hint; } $tigra_hints{$$cl->{"time"}} = $hint; #$$cl->{hint}=""; # Выводим <head_lines> верхних строк # и <tail_lines> нижних строк, # если эти параметры существуют my $output=""; if ($$cl->{"last_command"} eq "cat" && !$$cl->{"err"} && !($$cl->{"cline"} =~ /</)) { my $filename = $$cl->{"cline"}; $filename =~ s/.*\s+(\S+)\s*$/$1/; $Files{$filename}->{"content"} = $$cl->{"output"}; $Files{$filename}->{"source_command_id"} = $$cl->{"id"} } my @lines = split '\n', $$cl->{"output"}; if (( $Config{"head_lines"} || $Config{"tail_lines"} ) && $#lines > $Config{"head_lines"} + $Config{"tail_lines"} ) { # for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) { $output .= $lines[$i]."\n"; } $output .= $Config{"skip_text"}."\n"; my $start_line=$#lines-$Config{"tail_lines"}+1; for (my $i=$start_line; $i<= $#lines; $i++) { $output .= $lines[$i]."\n"; } } else { $output = $$cl->{"output"}; } $$cl->{short_output} = $output; # Обработка команд с одинаковым временем # Скорее всего они набраны с помощью tab-completion if (defined($prev_cl)) { if ($$prev_cl->{time} == $$cl->{time} && $$prev_cl->{nonce} == $$cl->{nonce}) { $tab_seq++; } else { $tab_seq=0; }; $$prev_cl->{tab_seq}=$tab_seq; # Обработка команд с одинаковым номером в истории # Скорее всего они набраны с помощью Ctrl-C #if ($$prev_cl->{history} == $$cl->{history}) { # $$prev_cl->{break}=1; #} } #Обработка пометок # Если несколько пометок (notes) идут подряд, # они все объединяются if ($$cl->{cline} =~ /l3shot/) { if ($$cl->{output} =~ m@Screenshot is written to.*/(.*)\.xwd@) { $$cl->{screenshot}="$1".$Config{l3shot_suffix}; } } if ($$cl->{cline} =~ /l3upload/) { if ($$cl->{output} =~ m@Uploaded file name is (.*)@) { $$cl->{screenshot}="$1"; } } if ($$cl->{cline}=~ m@cat[^#]*#([\^=v])\s*(.*)@) { my $note_operator = $1; my $note_title = $2; if ($note_operator eq "=") { $$cl->{"class"} = "note"; $$cl->{"note"} = $$cl->{"output"}; $$cl->{"note_title"} = $2; } else { my $j = $i; if ($note_operator eq "^") { $j--; $j-- while ($j >=0 && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); } elsif ($note_operator eq "v") { $j++; $j++ while ($j <= @Command_Lines && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); } $Command_Lines[$j]->{note_title}=$note_title; $Command_Lines[$j]->{note}.=$$cl->{output}; $$cl=0; } } elsif ($$cl->{cline}=~ /#([\^=v])(.*)/) { my $note_operator = $1; my $note_text = $2; if ($note_operator eq "=") { $$cl->{"class"} = "note"; $$cl->{"note"} = $note_text; } else { my $j=$i; if ($note_operator eq "^") { $j--; $j-- while ($j >=0 && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); } elsif ($note_operator eq "v") { $j++; $j++ while ($j <= @Command_Lines && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); } $Command_Lines[$j]->{note}.="$note_text\n"; $$cl=0; } } if ($$cl->{"class"} eq "note") { my $note_html = $$cl->{note}; $note_html = join ("\n", map ("<p>$_</p>", split (/-\n/, $note_html))); $note_html =~ s@(http:[a-zA-Z.0-9/?\_%-]*)@<a href='$1'>$1</a>@g; $note_html =~ s@(www\.[a-zA-Z.0-9/?\_%-]*)@<a href='$1'>$1</a>@g; $$cl->{"note_html"} = $note_html; } } } =cut Процедура print_command_lines выводит HTML-представление разобранного lab-скрипта. Разобранный lab-скрипт должен находиться в массиве @Command_Lines =cut sub print_command_lines_html { my @toc; # Оглавление my $note_number=0; my $result = q(); my $this_day_resut = q(); my $cl; my $last_tty=""; my $last_session=""; my $last_day=q(); my $last_wday=q(); my $first_command_of_the_day_unix_time=q(); my $human_readable_time=q(); my $in_range=0; my $current_command=0; my @known_commands; $Stat{LastCommand} ||= 0; $Stat{TotalCommands} ||= 0; $Stat{ErrorCommands} ||= 0; $Stat{MistypedCommands} ||= 0; my %new_entries_of = ( "1 1" => "программы пользователя", "2 8" => "программы администратора", "3 sh" => "команды интерпретатора", "4 script"=> "скрипты", ); COMMAND_LINE: for my $k (@Command_Lines_Index) { my $cl=$Command_Lines[$Command_Lines_Index[$current_command++]]; next unless $cl; next if $current_command < $Config{"start_from_command"}; last if $current_command > $Config{"start_from_command"} + $Config{"commands_to_show_at_a_go"}; # Пропускаем строки, которые противоречат фильтру # Если у нас недостаточно информации о том, подходит строка под фильтр или нет, # мы её выводим for my $filter_key (keys %filter) { next COMMAND_LINE if defined($cl->{local_session_id}) && defined($Sessions{$cl->{local_session_id}}->{$filter_key}) && $Sessions{$cl->{local_session_id}}->{$filter_key} ne $filter{$filter_key}; } # Набираем статистику # Хэш %Stat $Stat{FirstCommand} = $cl->{time} unless $Stat{FirstCommand}; if ($cl->{time} - $Stat{LastCommand} < $Config{stat_inactivity_interval}) { $Stat{TotalTime} += $cl->{time} - $Stat{LastCommand} } my $seconds_since_last_command = $cl->{time} - $Stat{LastCommand}; if ($Stat{LastCommand} > $cl->{time}) { $result .= "Время идёт вспять<br/>"; }; $Stat{LastCommand} = $cl->{time}; $Stat{TotalCommands}++; # Пропускаем строки, выходящие за границу "signature", # при условии, что границы указаны # Пропускаем неправильные/прерванные/другие команды if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { $in_range=1; next; } if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) { $in_range=0; next; } next if ($Config{"from"} && $Config{"to"} && !$in_range) || ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) || ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); # ## ## Начинается собственно вывод ## # ### Сначала обрабатываем границы разделов ### Если тип команды "note", это граница if ($cl->{class} eq "note") { $this_day_result .= "<tr><td colspan='6'>" . "<h4 id='note$note_number'>".$cl->{note_title}."</h4>" if $cl->{note_title} . "".$cl->{note_html}."<p/><p/></td></tr>"; if ($cl->{note_title}) { push @{$toc[@toc]},"<a href='#note$note_number'>".$cl->{note_title}."</a>"; $note_number++; } next; } my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); # Добавляем спереди 0 для удобочитаемости $min = "0".$min if $min =~ /^.$/; $hour = "0".$hour if $hour =~ /^.$/; $sec = "0".$sec if $sec =~ /^.$/; $class=$cl->{"class"}; $Stat{ErrorCommands}++ if $class =~ /wrong/; $Stat{MistypedCommands}++ if $class =~ /mistype/; # DAY CHANGE if ( $last_day ne $day) { $prev_unix_time=$first_command_of_the_day_unix_time; $first_command_of_the_day_unix_time = $cl->{time}; $human_readable_time = strftime "%D", localtime($prev_unix_time); if ($last_day) { # Вычисляем разность множеств. # Что-то вроде этого, если бы так можно было писать: # @new_commands = keys %frequency_of_command - @known_commands; # Выводим предыдущий день $result .= "<h3 id='day_on_sec_$prev_unix_time'>".$Day_Name[$last_wday]." ($human_readable_time)</h3>"; for my $entry_class (sort keys %new_entries_of) { my $table_caption = "Таблица ".$table_number++.".".$Day_Name[$last_wday] .". Новые ".$new_entries_of{$entry_class}; my $new_commands_section = make_new_entries_table( $table_caption, $entry_class=~/[0-9]+\s+(.*)/, \@known_commands); } @known_commands = keys %frequency_of_command; $result .= $this_day_result; } # Добавляем текущий день в оглавление $human_readable_time = strftime "%D", localtime($first_command_of_the_day_unix_time); push @toc, "<a href='#day_on_sec_$first_command_of_the_day_unix_time'>".$Day_Name[$wday]." ($human_readable_time)</a>\n"; $last_day=$day; $last_wday=$wday; $this_day_result = q(); } else { $this_day_result .= minutes_passed($seconds_since_last_command); } $this_day_result .= "<div class='command' id='command:".$cl->{"id"}."' >\n"; # CONSOLE CHANGE if ($cl->{"tty"} && $last_tty ne $cl->{"tty"} && 0) { my $tty = $cl->{"tty"}; $this_day_result .= "<div class='ttychange'>" . $tty ."</div>"; $last_tty=$cl->{"tty"}; } # Session change if ( $last_session ne $cl->{"local_session_id"}) { my $tty; if (defined $Sessions{$cl->{"local_session_id"}}->{"tty"}) { $this_day_result .= "<div class='ttychange'><a href='?local_session_id=".$cl->{"local_session_id"}."'>" . $Sessions{$cl->{"local_session_id"}}->{"tty"} ."</a></div>"; } $last_session=$cl->{"local_session_id"}; } # TIME if ($Config{"show_time"} =~ /^y/i) { $this_day_result .= "<div class='time'>$hour:$min:$sec</div>" } # COMMAND my $cline; $prompt_hint = join (" ", map("$_=$cl->{$_}", grep (!/^(output|short_output|diff)$/, sort(keys(%{$cl}))))); $cline = "<span title='$prompt_hint'>".$cl->{"prompt"}."</span>" ."<span onmouseover=\"myHint.show('".$cl->{time}."')\" onmouseout=\"myHint.hide()\">".$cl->{"cline"}."</span>"; $cline =~ s/\n//; if ($cl->{"hint"}) { # $cline = "<span title='$cl->{hint}' class='with_hint'>$cline</span>" ; $cline = "<span class='with_hint'>$cline</span>" ; } else { $cline = "<span class='without_hint'>$cline</span>"; } $this_day_result .= "<DIV class='fixed_div'><table cellpadding='0' cellspacing='0'><tr><td>\n<div class='cblock_$cl->{class}'>\n"; $this_day_result .= "<div class='cline'>" . $cline ; #cline $this_day_result .= "<span title='Код завершения ".$cl->{"err"}."'>\n" . "<img src='".$Config{frontend_ico_path}."/error.png'/>\n" . "</span>\n" if ($cl->{"err"} and not $cl->{tab_seq} and not $cl->{break}); $this_day_result .= "<span title='Tab completion ".$cl->{tab_seq}."'>\n" . "<img src='".$Config{frontend_ico_path}."/tab.png'/>\n" . "</span>\n" if $cl->{tab_seq}; $this_day_result .= "<span title='Ctrl-C pressed'>\n" . "<img src='".$Config{frontend_ico_path}."/break.png'/>\n" . "</span>\n" if ($cl->{break} and not $cl->{tab_seq}); $this_day_result .= "</div>\n"; #cline # OUTPUT my $last_command = $cl->{"last_command"}; if (!( $Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) || $Config{"suppress_pagers"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) || $Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}}) )) { $this_day_result .= "<pre class='output'>\n" . $cl->{short_output} . "</pre>\n"; } # DIFF $this_day_result .= "<pre class='diff'>".$cl->{"diff"}."</pre>" if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}); # SHOT $this_day_result .= "<img src='" .$Config{l3shot_path} .$cl->{"screenshot"} ."' alt ='screenshot id ".$cl->{"screenshot"} ."'/>" if ( $Config{"show_screenshots"} =~ /^y/i && $cl->{"screenshot"}); #NOTES if ( $Config{"show_notes"} =~ /^y/i && $cl->{"note"}) { my $note=$cl->{"note"}; $note =~ s/\n/<br\/>\n/msg; if (not $note =~ s@(http:[a-zA-Z.0-9/_?%-]*)@<a href='$1'>$1</a>@g) { $note =~ s@(www\.[a-zA-Z.0-9/_?%-]*)@<a href='$1'>$1</a>@g; }; $this_day_result .= "<div class='note'>"; $this_day_result .= "<div class='note_title'>".$cl->{note_title}."</div>" if $cl->{note_title}; $this_day_result .= "<div class='note_text'>".$note."</div>"; $this_day_result .= "</div>\n"; } # Вывод очередной команды окончен $this_day_result .= "</div>\n"; # cblock $this_day_result .= "</td></tr></table></DIV>\n" . "</div>\n"; # command } last: { $prev_unix_time=$first_command_of_the_day_unix_time; $first_command_of_the_day_unix_time = $cl->{time}; $human_readable_time = strftime "%D", localtime($prev_unix_time); $result .= "<h3 id='day_on_sec_$prev_unix_time'>".$Day_Name[$last_wday]." ($human_readable_time)</h3>"; for my $entry_class (keys %new_entries_of) { my $table_caption = "Таблица ".$table_number++.".".$Day_Name[$last_wday] . ". Новые ".$new_entries_of{$entry_class}; my $new_commands_section = make_new_entries_table( $table_caption, $entry_class=~/[0-9]+\s+(.*)/, \@known_commands); } @known_commands = keys %frequency_of_command; $result .= $this_day_result; } return ($result, collapse_list (\@toc)); } ############# # make_new_entries_table # # Напечатать таблицу неизвестных команд # # In: $_[0] table_caption # $_[1] entries_class # @_[2..] known_commands # Out: sub make_new_entries_table { my $table_caption; my $entries_class = shift; my @known_commands = @{$_[0]}; my $result = ""; my %count; my @new_commands = (); for my $c (keys %frequency_of_command, @known_commands) { $count{$c}++ } for my $c (keys %frequency_of_command) { push @new_commands, $c if $count{$c} != 2; } my $new_commands_section; if (@new_commands){ my $hint; for my $c (reverse sort { $frequency_of_command{$a} <=> $frequency_of_command{$b} } @new_commands) { $hint = make_comment($c); next unless $hint; my ($command, $hint) = $hint =~ m/(.*?) \s*- \s*(.*)/; next unless $command =~ s/\($entries_class\)//i; $new_commands_section .= "<tr><td valign='top'>$command</td><td>$hint</td></tr>"; } } if ($new_commands_section) { $result .= "<table class='new_commands_table' width='700' cellspacing='0' cellpadding='0'>" . "<tr class='new_commands_caption'>" . "<td colspan='2' align='right'>$table_caption</td>" . "</tr>" . "<tr class='new_commands_header'>" . "<td width=100>Команда</td><td width=600>Описание</td>" . "</tr>" . $new_commands_section . "</table>" } return $result; } ############# # minutes_passed # # # # In: $_[0] seconds_since_last_command # Out: "minutes passed" text sub minutes_passed { my $seconds_since_last_command = shift; my $result = ""; if ($seconds_since_last_command > 7200) { my $hours_passed = int($seconds_since_last_command/3600); my $passed_word = $hours_passed % 10 == 1 ? "прошла" : "прошло"; my $hours_word = $hours_passed % 10 == 1 ? "часа": "часов"; $result .= "<div class='much_time_passed'>" . $passed_word." >".$hours_passed." ".$hours_word . "</div>\n"; } elsif ($seconds_since_last_command > 600) { my $minutes_passed = int($seconds_since_last_command/60); my $passed_word = $minutes_passed % 100 > 10 && $minutes_passed % 100 < 20 ? "прошло" : $minutes_passed % 10 == 1 ? "прошла" : "прошло"; my $minutes_word = $minutes_passed % 100 > 10 && $minutes_passed % 100 < 20 ? "минут" : $minutes_passed % 10 == 1 ? "минута": $minutes_passed % 10 == 0 ? "минут" : $minutes_passed % 10 > 4 ? "минут" : "минуты"; if ($seconds_since_last_command < 1800) { $result .= "<div class='time_passed'>" . $passed_word." ".$minutes_passed." ".$minutes_word . "</div>\n"; } else { $result .= "<div class='much_time_passed'>" . $passed_word." ".$minutes_passed." ".$minutes_word . "</div>\n"; } } return $result; } ############# # print_all_txt # # Вывести журнал в текстовом формате # # In: $_[0] output_filename # Out: sub print_command_lines_txt { my $output_filename=$_[0]; my $note_number=0; my $result = q(); my $this_day_resut = q(); my $cl; my $last_tty=""; my $last_session=""; my $last_day=q(); my $last_wday=q(); my $in_range=0; my $current_command=0; my $cursor_position = 0; if ($Config{filter}) { # Инициализация фильтра for (split /&/,$Config{filter}) { my ($var, $val) = split /=/; $filter{$var} = $val || ""; } } COMMAND_LINE: for my $k (@Command_Lines_Index) { my $cl=$Command_Lines[$Command_Lines_Index[$current_command++]]; next unless $cl; # Пропускаем строки, которые противоречат фильтру # Если у нас недостаточно информации о том, подходит строка под фильтр или нет, # мы её выводим for my $filter_key (keys %filter) { next COMMAND_LINE if defined($cl->{local_session_id}) && defined($Sessions{$cl->{local_session_id}}->{$filter_key}) && $Sessions{$cl->{local_session_id}}->{$filter_key} ne $filter{$filter_key}; } # Пропускаем строки, выходящие за границу "signature", # при условии, что границы указаны # Пропускаем неправильные/прерванные/другие команды if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { $in_range=1; next; } if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) { $in_range=0; next; } next if ($Config{"from"} && $Config{"to"} && !$in_range) || ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) || ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) || ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); # ## ## Начинается собственно вывод ## # ### Сначала обрабатываем границы разделов ### Если тип команды "note", это граница if ($cl->{class} eq "note") { $this_day_result .= " === ".$cl->{note_title}." === \n" if $cl->{note_title}; $this_day_result .= $cl->{note}."\n"; next; } my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); # Добавляем спереди 0 для удобочитаемости $min = "0".$min if $min =~ /^.$/; $hour = "0".$hour if $hour =~ /^.$/; $sec = "0".$sec if $sec =~ /^.$/; $class=$cl->{"class"}; # DAY CHANGE if ( $last_day ne $day) { if ($last_day) { $result .= "== ".$Day_Name[$last_wday]." == \n"; $result .= $this_day_result; } $last_day = $day; $last_wday = $wday; $this_day_result = q(); } # CONSOLE CHANGE if ($cl->{"tty"} && $last_tty ne $cl->{"tty"} && 0) { my $tty = $cl->{"tty"}; $this_day_result .= " #l3: ------- другая консоль ----\n"; $last_tty=$cl->{"tty"}; } # Session change if ( $last_session ne $cl->{"local_session_id"}) { $this_day_result .= "# ------------------------------------------------------------" . " l3: local_session_id=".$cl->{"local_session_id"} . " ---------------------------------- \n"; $last_session=$cl->{"local_session_id"}; } # TIME my @nl_counter = split (/\n/, $result); $cursor_position=length($result) - @nl_counter; if ($Config{"show_time"} =~ /^y/i) { $this_day_result .= "$hour:$min:$sec" } # COMMAND $this_day_result .= " ".$cl->{"prompt"}.$cl->{"cline"}."\n"; if ($cl->{"err"}) { $this_day_result .= " #l3: err=".$cl->{'err'}."\n"; } # OUTPUT my $last_command = $cl->{"last_command"}; if (!( $Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) || $Config{"suppress_pagers"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) || $Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}}) )) { my $output = $cl->{short_output}; if ($output) { $output =~ s/^/ |/mg; } $this_day_result .= $output; } # DIFF if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) { my $diff = $cl->{"diff"}; $diff =~ s/^/ |/mg; $this_day_result .= $diff; }; # SHOT if ($Config{"show_screenshots"} =~ /^y/i && $cl->{"screenshot"}) { $this_day_result .= " #l3: screenshot=".$cl->{'screenshot'}."\n"; } #NOTES if ( $Config{"show_notes"} =~ /^y/i && $cl->{"note"}) { my $note=$cl->{"note"}; $note =~ s/\n/\n#^/msg; $this_day_result .= "#^ == ".$cl->{note_title}." ==\n" if $cl->{note_title}; $this_day_result .= "#^ ".$note."\n"; } } last: { $result .= "== ".$Day_Name[$last_wday]." == \n"; $result .= $this_day_result; } return $result; } ############# # print_edit_all_html # # Вывести страницу с текстовым представлением журнала для редактирования # # In: $_[0] output_filename # Out: sub print_edit_all_html { my $output_filename= shift; my $result; my $cursor_position = 0; $result = print_command_lines_txt; my $title = ">Журнал лабораторных работ. Правка"; $result = "<html>" ."<head>" ."<meta content='text/html; charset=utf-8' http-equiv='Content-Type' />" ."<link rel='stylesheet' href='$Config{frontend_css}' type='text/css'/>" ."<title>$title</title>" ."</head>" ."<script>" .$SetCursorPosition_JS ."</script>" ."<body onLoad='setCursorPosition(document.all.mytextarea, $cursor_position, $cursor_position+10)'>" ."<h1>Журнал лабораторных работ. Правка</h1>" ."<form>" ."<textarea rows='30' cols='100' wrap='off' id='mytextarea'>$result</textarea>" ."<br/><input type='submit' value='Сохранить' label='label'/>" ."</form>" ."<p>Внимательно правим, потом сохраняем</p>" ."<p>Строки, начинающиеся символами #l3: можно трогать, только если точно знаешь, что делаешь</p>" ."</body>" ."</html>"; if ($output_filename eq "-") { print $result; } else { open(OUT, ">", $output_filename) or die "Can't open $output_filename for writing\n"; binmode ":utf8"; print OUT "$result"; close(OUT); } } ############# # print_all_txt # # Вывести страницу с текстовым представлением журнала для редактирования # # In: $_[0] output_filename # Out: sub print_all_txt { my $result; $result = print_command_lines_txt; $result =~ s/>/>/g; $result =~ s/</</g; $result =~ s/&/&/g; if ($output_filename eq "-") { print $result; } else { open(OUT, ">:utf8", $output_filename) or die "Can't open $output_filename for writing\n"; print OUT "$result"; close(OUT); } } ############# # print_all_html # # # # In: $_[0] output_filename # Out: sub print_all_html { my $output_filename=$_[0]; my $result; my ($command_lines,$toc) = print_command_lines_html; my $files_section = print_files_html; $result = $debug_output; $result .= print_header_html($toc); # $result.= join " <br/>", keys %Sessions; # for my $sess (keys %Sessions) { # $result .= join " ", keys (%{$Sessions{$sess}}); # $result .= "<br/>"; # } $result.= "<h2 id='log'>Журнал</h2>" . $command_lines; $result.= "<h2 id='files'>Файлы</h2>" . $files_section if $files_section; $result.= "<h2 id='stat'>Статистика</h2>" . print_stat_html; $result.= "<h2 id='help'>Справка</h2>" . $Html_Help . "<br/>"; $result.= "<h2 id='about'>О программе</h2>". $Html_About. "<br/>"; $result.= print_footer_html; if ($output_filename eq "-") { binmode STDOUT, ":utf8"; print $result; } else { open(OUT, ">:utf8", $output_filename) or die "Can't open $output_filename for writing\n"; print OUT $result; close(OUT); } } ############# # print_header_html # # # # In: $_[0] Содержание # Out: Распечатанный заголовок sub print_header_html { my $toc = $_[0]; my $course_name = $Config{"course-name"}; my $course_code = $Config{"course-code"}; my $course_date = $Config{"course-date"}; my $course_center = $Config{"course-center"}; my $course_trainer = $Config{"course-trainer"}; my $course_student = $Config{"course-student"}; my $title = "Журнал лабораторных работ"; $title .= " -- ".$course_student if $course_student; if ($course_date) { $title .= " -- ".$course_date; $title .= $course_code ? "/".$course_code : ""; } else { $title .= " -- ".$course_code if $course_code; } # Управляющая форма my $control_form .= "<div class='visibility_form' title='Выберите какие элементы должны быть показаны в журнале'>" . "<span class='header'>Видимые элементы</span>" . "<span class='window_controls'><a href='' onclick='' title='свернуть форму управления'>_</a> <a href='' onclick='' title='закрыть форму управления'>x</a></span>" . "<div><form>\n"; for my $element (sort keys %Elements_Visibility) { my ($skip, @e) = split /\s+/, $element; my $showhide = join "", map { "ShowHide('$_');" } @e ; $control_form .= "<div><input type='checkbox' name='$e[0]' onclick=\"$showhide\" checked>". $Elements_Visibility{$element}. "</input></div>"; } $control_form .= "</form>\n" . "</div>\n"; # Управляющая форма отключена # Она слишком сильно мешает, нужно что-то переделать $control_form = ""; my $tigra_hints_array=tigra_hints_generate; my $result; $result = <<HEADER; <html> <head> <meta content='text/html; charset=utf-8' http-equiv='Content-Type' /> <link rel='stylesheet' href='$Config{frontend_css}' type='text/css'/> <title>$title</title> </head> <body> <!--<script> $Html_JavaScript </script>--> <!-- vvv Tigra Hints vvv --> <script language="JavaScript" src="/tigra/hints.js"></script> <!--<script language="JavaScript" src="/tigra/hints_cfg.js"></script>--> <script>$tigra_hints_array</script> <style> /* a class for all Tigra Hints boxes, TD object */ .hintsClass {text-align: left; font-size:80%; font-family: Verdana, Arial, Helvetica; background-color:#ffffee; padding: 0px 0px 0px 0px;} /* this class is used by Tigra Hints wrappers */ .row {background: white;} .bl2 {border: 1px solid #e68200; background:url(/tigra/block/bl2.gif) 0 100% no-repeat; text-align:left} .bl {background:url(/tigra/block/bl2.gif) 0 100% no-repeat; text-align:left} .br {background:url(/tigra/block/br2.gif) 100% 100% no-repeat} .tl {background:url(/tigra/block/tl2.gif) 0 0 no-repeat} .tr {background:url(/tigra/block/tr2.gif) 100% 0 no-repeat; padding:10px} .tr2 {background:url(/tigra/block/tr2.gif) 100% 0 no-repeat} .t {background:url(/tigra/block/dot2.gif) 0 0 repeat-x} .b {background:url(/tigra/block/dot2.gif) 0 100% repeat-x} .l {background:url(/tigra/block/dot2.gif) 0 0 repeat-y} .r {background:url(/tigra/block/dot2.gif) 100% 0 repeat-y} </style> <!-- ^^^ Tigra Hints ^^^ --> <!-- .bl2 {border: 1px solid #e68200; background:url(/tigra/block/bl2.gif) 0 100% no-repeat; width:20em; text-align:center} .bl {background:url(/tigra/block/bl2.gif) 0 100% no-repeat; width:20em; text-align:center} .br {background:url(/tigra/block/br2.gif) 100% 100% no-repeat} .tl {background:url(/tigra/block/tl2.gif) 0 0 no-repeat} .tr {background:url(/tigra/block/tr2.gif) 100% 0 no-repeat; padding:10px} .tr2 {background:url(/tigra/block/tr2.gif) 100% 0 no-repeat} .t {background:url(/tigra/block/dot2.gif) 0 0 repeat-x; width:20em} .b {background:url(/tigra/block/dot2.gif) 0 100% repeat-x} .l {background:url(/tigra/block/dot2.gif) 0 0 repeat-y} .r {background:url(/tigra/block/dot2.gif) 100% 0 repeat-y} --> <div class='edit_link'> [ <a href='?action=edit&$filter_url'>править</a> ] </div> <h1 onmouseover="myHint.show('1')" onmouseout="myHint.hide()" class='lined_header'>Журнал лабораторных работ</h1> HEADER if ( $course_student || $course_trainer || $course_name || $course_code || $course_date || $course_center) { $result .= "<p>"; $result .= "Выполнил $course_student<br/>" if $course_student; $result .= "Проверил $course_trainer <br/>" if $course_trainer; $result .= "Курс " if $course_name || $course_code || $course_date; $result .= "$course_name " if $course_name; $result .= "($course_code)" if $course_code; $result .= ", $course_date<br/>" if $course_date; $result .= "Учебный центр $course_center <br/>" if $course_center; $result .= "Фильтр ".join(" ", map("$filter{$_}=$_", keys %filter))."<br/>" if %filter; $result .= "</p>"; } $result .= <<HEADER; <table width='100%'> <tr> <td width='*'> <table border=0 id='toc' class='toc'> <tr> <td> <div class='toc_title'>Содержание</div> <ul> <li><a href='#log'>Журнал</a></li> <ul>$toc</ul> <li><a href='#files'>Файлы</a></li> <li><a href='#stat'>Статистика</a></li> <li><a href='#help'>Справка</a></li> <li><a href='#about'>О программе</a></li> </ul> </td> </tr> </table> </td> <td valign='top' width=200>$control_form</td> </tr> </table> HEADER return $result; } ############# # print_footer_html # # # # # sub print_footer_html { return "</body>\n</html>\n"; } ############# # print_stat_html # # # # In: # Out: sub print_stat_html { %StatNames = ( FirstCommand => "Время первой команды журнала", LastCommand => "Время последней команды журнала", TotalCommands => "Количество командных строк в журнале", ErrorsPercentage => "Процент команд с ненулевым кодом завершения, %", MistypesPercentage => "Процент синтаксически неверно набранных команд, %", TotalTime => "Суммарное время работы с терминалом <sup><font size='-2'>*</font></sup>, час", CommandsPerTime => "Количество командных строк в единицу времени, команда/мин", CommandsFrequency => "Частота использования команд", RareCommands => "Частота использования этих команд < 0.5%", ); @StatOrder = ( FirstCommand, LastCommand, TotalCommands, ErrorsPercentage, MistypesPercentage, TotalTime, CommandsPerTime, CommandsFrequency, RareCommands, ); # Подготовка статистики к выводу # Некоторые значения пересчитываются! # Дальше их лучше уже не использовать!!! my %CommandsFrequency = %frequency_of_command; $Stat{TotalTime} ||= 0; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{FirstCommand} || 0); $Stat{FirstCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec, $year+1900, $mon+1, $mday; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{LastCommand} || 0); $Stat{LastCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec, $year+1900, $mon+1, $mday; if ($Stat{TotalCommands}) { $Stat{ErrorsPercentage} = sprintf "%5.2f", $Stat{ErrorCommands}*100/$Stat{TotalCommands}; $Stat{MistypesPercentage} = sprintf "%5.2f", $Stat{MistypedCommands}*100/$Stat{TotalCommands}; } $Stat{CommandsPerTime} = sprintf "%5.2f", $Stat{TotalCommands}*60/$Stat{TotalTime} if $Stat{TotalTime}; $Stat{TotalTime} = sprintf "%5.2f", $Stat{TotalTime}/60/60; my $total_commands=0; for $command (keys %CommandsFrequency){ $total_commands += $CommandsFrequency{$command}; } if ($total_commands) { for $command (reverse sort {$CommandsFrequency{$a} <=> $CommandsFrequency{$b}} keys %CommandsFrequency){ my $command_html; my $percentage = sprintf "%5.2f",$CommandsFrequency{$command}*100/$total_commands; if ($percentage < 0.5) { my $hint = make_comment($command); $command_html = "$command"; $command_html = "<span title='$hint' class='with_hint'>$command_html</span>" if $hint; $command_html = "<span class='without_hint'>$command_html</span>" if not $hint; my $command_html = "<tt>$command_html</tt>"; $Stat{RareCommands} .= $command_html."<sub><font size='-2'>".$CommandsFrequency{$command}."</font></sub> , "; } else { my $hint = make_comment($command); $command_html = "$command"; $command_html = "<span title='$hint' class='with_hint'>$command_html</span>" if $hint; $command_html = "<span class='without_hint'>$command_html</span>" if not $hint; my $command_html = "<tt>$command_html</tt>"; $percentage = sprintf "%5.2f",$percentage; $Stat{CommandsFrequency} .= "<tr><td>".$command_html."</td><td>".$CommandsFrequency{$command}."</td>". "<td>|".("="x int($CommandsFrequency{$command}*100/$total_commands))."| $percentage%</td></tr>"; } } $Stat{CommandsFrequency} = "<table>".$Stat{CommandsFrequency}."</table>"; $Stat{RareCommands} =~ s/, $// if $Stat{RareCommands}; } my $result = q(); for my $stat (@StatOrder) { next unless $Stat{"$stat"}; $result .= "<tr valign='top'><td width='300'>".$StatNames{"$stat"}."</td><td>".$Stat{"$stat"}."</td></tr>" } $result = "<table>$result</table>" . "<font size='-2'>____<br/>*) Интервалы неактивности длительностью " . ($Config{stat_inactivity_interval}/60) . " минут и более не учитываются</font></br>"; return $result; } sub collapse_list($) { my $res = ""; for my $elem (@{$_[0]}) { if (ref $elem eq "ARRAY") { $res .= "<ul>".collapse_list($elem)."</ul>"; } else { $res .= "<li>".$elem."</li>"; } } return $res; } sub print_files_html { my $result = qq(); my @toc; for my $file (sort keys %Files) { my $div_id = "file:$file"; $div_id =~ s@/@_@g; push @toc, "<a href='#$div_id'>$file</a>"; $result .= "<div class='filename' id='$div_id'>".$file."</div>\n" . "<div class='file_navigation'><a href='#command:".$Files{$file}->{source_command_id}."'>".">"."</a></div>" . "<div class='filedata'><pre>".$Files{$file}->{content}."</pre></div>"; } if ($result) { return "<div class='files_toc'>".collapse_list(\@toc)."</div>".$result; } else { return ""; } } sub init_variables { $Html_Help = <<HELP; Для того чтобы использовать LiLaLo, не нужно знать ничего особенного: всё происходит само собой. Однако, чтобы ведение и последующее использование журналов было как можно более эффективным, желательно иметь в виду следующее: <ol> <li><p> В журнал автоматически попадают все команды, данные в любом терминале системы. </p></li> <li><p> Для того чтобы убедиться, что журнал на текущем терминале ведётся, и команды записываются, дайте команду w. В поле WHAT, соответствующем текущему терминалу, должна быть указана программа script. </p></li> <li><p> Команды, при наборе которых были допущены синтаксические ошибки, выводятся перечёркнутым текстом: <table> <tr class='command'> <td class='script'> <pre class='_mistyped_cline'> \$ l s-l</pre> <pre class='_mistyped_output'>bash: l: command not found </pre> </td> </tr> </table> <br/> </p></li> <li><p> Если код завершения команды равен нулю, команда была выполнена без ошибок. Команды, код завершения которых отличен от нуля, выделяются цветом. <table> <tr class='command'> <td class='script'> <pre class='_wrong_cline'> \$ test 5 -lt 4</pre> </pre> </td> </tr> </table> Обратите внимание на то, что код завершения команды может быть отличен от нуля не только в тех случаях, когда команда была выполнена с ошибкой. Многие команды используют код завершения, например, для того чтобы показать результаты проверки <br/> </p></li> <li><p> Команды, ход выполнения которых был прерван пользователем, выделяются цветом. <table> <tr class='command'> <td class='script'> <pre class='_interrupted_cline'> \$ find / -name abc</pre> <pre class='interrupted_output'>find: /home/devi-orig/.gnome2: Keine Berechtigung find: /home/devi-orig/.gnome2_private: Keine Berechtigung find: /home/devi-orig/.nautilus/metafiles: Keine Berechtigung find: /home/devi-orig/.metacity: Keine Berechtigung find: /home/devi-orig/.inkscape: Keine Berechtigung ^C </pre> </td> </tr> </table> <br/> </p></li> <li><p> Команды, выполненные с привилегиями суперпользователя, выделяются слева красной чертой. <table> <tr class='command'> <td class='script'> <pre class='_root_cline'> # id</pre> <pre class='_root_output'> uid=0(root) gid=0(root) Gruppen=0(root) </pre> </td> </tr> </table> <br/> </p></li> <li><p> Изменения, внесённые в текстовый файл с помощью редактора, запоминаются и показываются в журнале в формате ed. Строки, начинающиеся символом "<", удалены, а строки, начинающиеся символом ">" -- добавлены. <table> <tr class='command'> <td class='script'> <pre class='cline'> \$ vi ~/.bashrc</pre> <table><tr><td width='5'/><td class='diff'><pre>2a3,5 > if [ -f /usr/local/etc/bash_completion ]; then > . /usr/local/etc/bash_completion > fi </pre></td></tr></table></td> </tr> </table> <br/> </p></li> <li><p> Для того чтобы изменить файл в соответствии с показанными в диффшоте изменениями, можно воспользоваться командой patch. Нужно скопировать изменения, запустить программу patch, указав в качестве её аргумента файл, к которому применяются изменения, и всавить скопированный текст: <table> <tr class='command'> <td class='script'> <pre class='cline'> \$ patch ~/.bashrc</pre> </td> </tr> </table> В данном случае изменения применяются к файлу ~/.bashrc </p></li> <li><p> Для того чтобы получить краткую справочную информацию о команде, нужно подвести к ней мышь. Во всплывающей подсказке появится краткое описание команды. </p> <p> Если справочная информация о команде есть, команда выделяется голубым фоном, например: <span class="with_hint" title="главный текстовый редактор Unix">vi</span>. Если справочная информация отсутствует, команда выделяется розовым фоном, например: <span class="without_hint">notepad.exe</span>. Справочная информация может отсутствовать в том случае, если (1) команда введена неверно; (2) если распознавание команды LiLaLo выполнено неверно; (3) если информация о команде неизвестна LiLaLo. Последнее возможно для редких команд. </p></li> <li><p> Большие, в особенности многострочные, всплывающие подсказки лучше всего показываются браузерами KDE Konqueror, Apple Safari и Microsoft Internet Explorer. В браузерах Mozilla и Firefox они отображаются не полностью, а вместо перевода строки выводится специальный символ. </p></li> <li><p> Время ввода команды, показанное в журнале, соответствует времени <i>начала ввода командной строки</i>, которое равно тому моменту, когда на терминале появилось приглашение интерпретатора </p></li> <li><p> Имя терминала, на котором была введена команда, показано в специальном блоке. Этот блок показывается только в том случае, если терминал текущей команды отличается от терминала предыдущей. </p></li> <li><p> Вывод не интересующих вас в настоящий момент элементов журнала, таких как время, имя терминала и других, можно отключить. Для этого нужно воспользоваться <a href='#visibility_form'>формой управления журналом</a> вверху страницы. </p></li> <li><p> Небольшие комментарии к командам можно вставлять прямо из командной строки. Комментарий вводится прямо в командную строку, после символов #^ или #v. Символы ^ и v показывают направление выбора команды, к которой относится комментарий: ^ - к предыдущей, v - к следующей. Например, если в командной строке было введено: <pre class='cline'> \$ whoami </pre> <pre class='output'> user </pre> <pre class='cline'> \$ #^ Интересно, кто я? </pre> в журнале это будет выглядеть так: <pre class='cline'> \$ whoami </pre> <pre class='output'> user </pre> <table class='note'><tr><td width='100%' class='note_text'> <tr> <td> Интересно, кто я?<br/> </td></tr></table> </p></li> <li><p> Если комментарий содержит несколько строк, его можно вставить в журнал следующим образом: <pre class='cline'> \$ whoami </pre> <pre class='output'> user </pre> <pre class='cline'> \$ cat > /dev/null #^ Интересно, кто я? </pre> <pre class='output'> Программа whoami выводит имя пользователя, под которым мы зарегистрировались в системе. - Она не может ответить на вопрос о нашем назначении в этом мире. </pre> В журнале это будет выглядеть так: <table> <tr class='command'> <td class='script'> <pre class='cline'> \$ whoami</pre> <pre class='output'>user </pre> <table class='note'><tr><td class='note_title'>Интересно, кто я?</td></tr><tr><td width='100%' class='note_text'> Программа whoami выводит имя пользователя, под которым<br/> мы зарегистрировались в системе.<br/> <br/> Она не может ответить на вопрос о нашем назначении<br/> в этом мире.<br/> </td></tr></table> </td> </tr> </table> Для разделения нескольких абзацев между собой используйте символ "-", один в строке. <br/> </p></li> <li><p> Комментарии, не относящиеся непосредственно ни к какой из команд, добавляются точно таким же способом, только вместо симолов #^ или #v нужно использовать символы #= </p></li> <p><li> Содержимое файла может быть показано в журнале. Для этого его нужно вывести с помощью программы cat. Если вывод команды отметить симоволами #!, содержимое файла будет показано в журнале в специально отведённой для этого секции. </li></p> <p> <li> Для того чтобы вставить скриншот интересующего вас окна в журнал, нужно воспользоваться командой l3shot. После того как команда вызвана, нужно с помощью мыши выбрать окно, которое должно быть в журнале. </li> </p> <p> <li> Команды в журнале расположены в хронологическом порядке. Если две команды давались одна за другой, но на разных терминалах, в журнале они будут рядом, даже если они не имеют друг к другу никакого отношения. <pre> 1 2 3 4 </pre> Группы команд, выполненных на разных терминалах, разделяются специальной линией. Под этой линией в правом углу показано имя терминала, на котором выполнялись команды. Для того чтобы посмотреть команды только одного сенса, нужно щёкнуть по этому названию. </li> </p> </ol> HELP $Html_About = <<ABOUT; <p> <a href='http://xgu.ru/lilalo/'>LiLaLo</a> (L3) расшифровывается как Live Lab Log.<br/> Программа разработана для повышения эффективности обучения Unix/Linux-системам.<br/> (c) Игорь Чубин, 2004-2008<br/> </p> ABOUT $Html_About.='$Id: l3-frontend,v 1.45 2008-03-13 10:19:42 igor Exp $ </p>'; $Html_JavaScript = <<JS; function getElementsByClassName(Class_Name) { var Result=new Array(); var All_Elements=document.all || document.getElementsByTagName('*'); for (i=0; i<All_Elements.length; i++) if (All_Elements[i].className==Class_Name) Result.push(All_Elements[i]); return Result; } function ShowHide (name) { elements=getElementsByClassName(name); for(i=0; i<elements.length; i++) if (elements[i].style.display == "none") elements[i].style.display = ""; else elements[i].style.display = "none"; //if (elements[i].style.visibility == "hidden") // elements[i].style.visibility = "visible"; //else // elements[i].style.visibility = "hidden"; } function filter_by_output(text) { var jjj=0; elements=getElementsByClassName('command'); for(i=0; i<elements.length; i++) { subelems = elements[i].getElementsByTagName('pre'); for(j=0; j<subelems.length; j++) { if (subelems[j].className = 'output') { var str = new String(subelems[j].nodeValue); if (jjj != 1) { alert(str); jjj=1; } if (str.indexOf(text) >0) subelems[j].style.display = "none"; else subelems[j].style.display = ""; } } } } JS $SetCursorPosition_JS = <<JS; function setCursorPosition(oInput,oStart,oEnd) { oInput.focus(); if( oInput.setSelectionRange ) { oInput.setSelectionRange(oStart,oEnd); } else if( oInput.createTextRange ) { var range = oInput.createTextRange(); range.collapse(true); range.moveEnd('character',oEnd); range.moveStart('character',oStart); range.select(); } } JS %Search_Machines = ( "google" => { "query" => "http://www.google.com/search?q=" , "icon" => "$Config{frontend_google_ico}" }, "freebsd" => { "query" => "http://www.freebsd.org/cgi/man.cgi?query=", "icon" => "$Config{frontend_freebsd_ico}" }, "linux" => { "query" => "http://man.he.net/?topic=", "icon" => "$Config{frontend_linux_ico}"}, "opennet" => { "query" => "http://www.opennet.ru/search.shtml?words=", "icon" => "$Config{frontend_opennet_ico}"}, "local" => { "query" => "http://www.freebsd.org/cgi/man.cgi?query=", "icon" => "$Config{frontend_local_ico}" }, ); %Elements_Visibility = ( "0 new_commands_table" => "новые команды", "1 diff" => "редактор", "2 time" => "время", "3 ttychange" => "терминал", "4 wrong_output wrong_cline wrong_root_output wrong_root_cline" => "команды с ненулевым кодом завершения", "5 mistyped_output mistyped_cline mistyped_root_output mistyped_root_cline" => "неверно набранные команды", "6 interrupted_output interrupted_cline interrupted_root_output interrupted_root_cline" => "прерванные команды", "7 tab_completion_output tab_completion_cline" => "продолжение с помощью tab" ); @Day_Name = qw/ Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота /; @Month_Name = qw/ Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь /; @Of_Month_Name = qw/ Января Февраля Марта Апреля Мая Июня Июля Августа Сентября Октября Ноября Декабря /; } # Временно удалённый код # Возможно, он не понадобится уже никогда sub search_by { my $sm = shift; my $topic = shift; $topic =~ s/ /+/; return "<a href='". $Search_Machines{$sm}->{"query"}."$topic'><img width='16' height='16' src='". $Search_Machines{$sm}->{"icon"}."' border='0'/></a>"; } ######################################################################################## # # mywi # # # # # # # sub mywi_init { our $MyWiFile = "/home/igor/mywi/mywi.txt"; our $MyWiLog = "/home/igor/mywi/mywi.log"; our $section=""; our @MywiTXT; # Массив текстовых записей mywi our %MywiHASH; # Хэш массивов записей our %Query; load_mywitxt($MyWiFile, \@MywiTXT, \%MywiHASH); } sub mywi_process_query($) # # Сделать подсказку по заданному запросу # $_[0] - тема для подсказки # # Возвращает: # строку-подсказку # { my $query = shift; parse_query($query, \%Query); $result = search_in_txt(\%Query, \@MywiTXT, \%MywiHASH); if (!$result) { #add_to_log(\%Query, $MyWiLog); return "$query nothing appropriate. Logged. ".join (";",%Query); } return $result; } #################################################################################### # private section #################################################################################### sub load_mywitxt # # Загрузить файл с записями Mywi_TXT # в массив # $_[0] - указатель на массив для загрузки # $_[1] - имя файла для загрузки # { my $MyWiFile = $_[0]; my $MywiTXT = $_[1]; my $MywiHASH = $_[2]; open (MW, "$MyWiFile") or die "Can't open $MyWiFile for reading"; binmode MW, ":utf8"; @{$MywiTXT} = <MW>; close (MWF); for my $mywi_line (@{$MywiTXT}) { my $topic = $mywi_line; $topic =~ s@\s*\(.*\n@@; push @{$$MywiHASH{"$topic"}}, $mywi_line; # $MywiHASH{"$topic"} .= $mywi_line; } } sub parse_query # # Строка запроса: # [format:]topic[(section)] # Элементы format и topic являются не обязательными # # $_[0] - строка запроса # $_[1] - ссылка на хэш запроса # { my $query_string = shift; my $query_hash = shift; %{$query_hash} = ( "format" => "txt", "section" => "", "topic" => "", ); if ($query_string =~ s/^([^:]*)://) { $query_hash->{"format"} = $1 || "txt"; } if ($query_string =~ s/\(([^(]*)\)$//) { $query_hash->{"section"} = $1 || ""; } $query_hash->{"topic"} = $query_string; } sub search_in_txt # # Выполнить поиск в текстовой базе # по известному запросу # $_[0] -- ссылка на хэш запроса # $_[1] -- ссылка на массив текстовых записей # $_[2] -- ссылка на хэш массивов текстовых записей # Результат: # найденная текстовая запись в заданном формате # { my %Query = %{$_[0]}; my %MywiHASH = %{$_[2]}; my $topic = $Query{"topic"}; my $section = $Query{"section"}; my $result = ""; return join("\n",@{$MywiHASH{"$topic"}})."\n"; for my $l (@{$$_[2]{$topic}}) { # for my $l (@{$_[1]}) { my $line = $l; if ( ($section and $line =~ /^\s*\Q$topic\E\s*\($section*\)\s*-/ ) or (not $section and $line =~ /^\s*\Q$topic\E\s*(\([^)]*\)?)\s*-/) ) { $line =~ s/^.* -//mg if ($Config{"short"}); $result .= "<para>$line</para>"; } } return $result; } sub add_to_log($$) # # Если в базе отсутствует информация по данной теме, # сделать предположение доступным способом # и добавить его в базу # или просто сделать отметку о необходимости # расширения базы # # Добавить запись в журнал # $_[0] - запись (ссылка на хэш) # $_[1] - имя файла-журнала # { my $query = $_[0]; my $MyWiLog = $_[1]; open (MWF, ">>:utf8", $MyWiLog) or die "Can't open $MyWiLog for writing"; my $my_guess = mywi_guess($query); print MWF "$my_guess\n"; close(MWF); } sub mywi_guess($) # Сформировать исходную строку для журнала по заданному запросу # Если секция принадлежит 0..9, в качестве основы для результирующего текста использовать whatis # $_[0] - запись (ссылка на хэш) # # Возвращает: # строку-предположение { my %query = %{$_[0]}; my $topic = $query{"topic"}; my $section = $query{"section"}; my $result = "$topic($section)"; if (!$section or $section =~ /^[1-9]$/) { # Запрос из категории 1-9 # Об этом может знать whatis $result = `LANG=C whatis -- "$topic"`; if ($result =~ /nothing appropriate/i) { $result = $topic; $result .= "($section)" if $section; } else { 1 while ($result =~ s/(\s+)-(\s+)/$1+$2/sg); $result =~ s/\s+\(/(/; chomp $result; } } return $result; }
Время первой команды журнала | 09:18:31 2006- 9-12 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Время последней команды журнала | 07:34:01 2011- 9-12 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Количество командных строк в журнале | 101 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Процент команд с ненулевым кодом завершения, % | 7.92 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Процент синтаксически неверно набранных команд, % | 0.99 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Суммарное время работы с терминалом *, час | 0.65 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Количество командных строк в единицу времени, команда/мин | 2.60 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Частота использования команд |
|
В журнал автоматически попадают все команды, данные в любом терминале системы.
Для того чтобы убедиться, что журнал на текущем терминале ведётся, и команды записываются, дайте команду w. В поле WHAT, соответствующем текущему терминалу, должна быть указана программа script.
Команды, при наборе которых были допущены синтаксические ошибки, выводятся перечёркнутым текстом:
$ l s-l bash: l: command not found |
Если код завершения команды равен нулю, команда была выполнена без ошибок. Команды, код завершения которых отличен от нуля, выделяются цветом.
$ test 5 -lt 4 |
Команды, ход выполнения которых был прерван пользователем, выделяются цветом.
$ find / -name abc find: /home/devi-orig/.gnome2: Keine Berechtigung find: /home/devi-orig/.gnome2_private: Keine Berechtigung find: /home/devi-orig/.nautilus/metafiles: Keine Berechtigung find: /home/devi-orig/.metacity: Keine Berechtigung find: /home/devi-orig/.inkscape: Keine Berechtigung ^C |
Команды, выполненные с привилегиями суперпользователя, выделяются слева красной чертой.
# id uid=0(root) gid=0(root) Gruppen=0(root) |
Изменения, внесённые в текстовый файл с помощью редактора, запоминаются и показываются в журнале в формате ed. Строки, начинающиеся символом "<", удалены, а строки, начинающиеся символом ">" -- добавлены.
$ vi ~/.bashrc
|
Для того чтобы изменить файл в соответствии с показанными в диффшоте изменениями, можно воспользоваться командой patch. Нужно скопировать изменения, запустить программу patch, указав в качестве её аргумента файл, к которому применяются изменения, и всавить скопированный текст:
$ patch ~/.bashrc |
Для того чтобы получить краткую справочную информацию о команде, нужно подвести к ней мышь. Во всплывающей подсказке появится краткое описание команды.
Если справочная информация о команде есть, команда выделяется голубым фоном, например: vi. Если справочная информация отсутствует, команда выделяется розовым фоном, например: notepad.exe. Справочная информация может отсутствовать в том случае, если (1) команда введена неверно; (2) если распознавание команды LiLaLo выполнено неверно; (3) если информация о команде неизвестна LiLaLo. Последнее возможно для редких команд.
Большие, в особенности многострочные, всплывающие подсказки лучше всего показываются браузерами KDE Konqueror, Apple Safari и Microsoft Internet Explorer. В браузерах Mozilla и Firefox они отображаются не полностью, а вместо перевода строки выводится специальный символ.
Время ввода команды, показанное в журнале, соответствует времени начала ввода командной строки, которое равно тому моменту, когда на терминале появилось приглашение интерпретатора
Имя терминала, на котором была введена команда, показано в специальном блоке. Этот блок показывается только в том случае, если терминал текущей команды отличается от терминала предыдущей.
Вывод не интересующих вас в настоящий момент элементов журнала, таких как время, имя терминала и других, можно отключить. Для этого нужно воспользоваться формой управления журналом вверху страницы.
Небольшие комментарии к командам можно вставлять прямо из командной строки. Комментарий вводится прямо в командную строку, после символов #^ или #v. Символы ^ и v показывают направление выбора команды, к которой относится комментарий: ^ - к предыдущей, v - к следующей. Например, если в командной строке было введено:
$ whoami
user
$ #^ Интересно, кто я?в журнале это будет выглядеть так:
$ whoami
user
Интересно, кто я? |
Если комментарий содержит несколько строк, его можно вставить в журнал следующим образом:
$ whoami
user
$ cat > /dev/null #^ Интересно, кто я?
Программа whoami выводит имя пользователя, под которым мы зарегистрировались в системе. - Она не может ответить на вопрос о нашем назначении в этом мире.В журнале это будет выглядеть так:
$ whoami user
|
Комментарии, не относящиеся непосредственно ни к какой из команд, добавляются точно таким же способом, только вместо симолов #^ или #v нужно использовать символы #=
1 2 3 4Группы команд, выполненных на разных терминалах, разделяются специальной линией. Под этой линией в правом углу показано имя терминала, на котором выполнялись команды. Для того чтобы посмотреть команды только одного сенса, нужно щёкнуть по этому названию.
LiLaLo (L3) расшифровывается как Live Lab Log.
Программа разработана для повышения эффективности обучения Unix/Linux-системам.
(c) Игорь Чубин, 2004-2008