rev |
line source |
devi@52
|
1 #!/usr/bin/perl -w
|
devi@23
|
2
|
devi@23
|
3 #
|
devi@23
|
4 # (c) Igor Chubin, imchubin@mail.ru, 2004-2005
|
devi@23
|
5 #
|
devi@23
|
6
|
devi@50
|
7
|
devi@50
|
8 ## Эта строчка добавлена из блокнота Windows
|
devi@50
|
9 ## Надо отдать должное, он каким-то образом научился понимать кодировку
|
devi@50
|
10
|
devi@23
|
11 use strict;
|
devi@25
|
12 use POSIX;
|
devi@23
|
13 use Term::VT102;
|
devi@23
|
14 use Text::Iconv;
|
devi@23
|
15 use Time::Local 'timelocal_nocheck';
|
devi@27
|
16 use IO::Socket;
|
devi@23
|
17
|
devi@32
|
18 use lib "/usr/local/bin";
|
devi@23
|
19 use l3config;
|
devi@23
|
20
|
devi@23
|
21
|
devi@23
|
22 our @Command_Lines;
|
devi@23
|
23 our @Command_Lines_Index;
|
devi@28
|
24 our %Diffs;
|
devi@27
|
25 our %Sessions;
|
devi@23
|
26
|
devi@23
|
27 our %Commands_Stat; # Statistics about commands usage
|
devi@23
|
28 our %Files_Stat; # Statistics about commands usage
|
devi@23
|
29
|
devi@25
|
30 our %Script_Files; # Информация о позициях в скрипт-файлах,
|
devi@25
|
31 # до которых уже выполнен разбор
|
devi@25
|
32 # и информация о времени модификации файла
|
devi@25
|
33 # $Script_Files{$file}->{size}
|
devi@25
|
34 # $Script_Files{$file}->{tell}
|
devi@25
|
35
|
devi@25
|
36 our $Killed =0; # В режиме демона -- процесс получил сигнал о завершении
|
devi@23
|
37
|
devi@23
|
38 sub init_variables;
|
devi@23
|
39 sub main;
|
devi@23
|
40
|
devi@23
|
41 sub load_diff_files;
|
devi@23
|
42 sub bind_diff;
|
devi@23
|
43 sub extract_from_cline;
|
devi@23
|
44 sub load_command_lines;
|
devi@23
|
45 sub sort_command_lines;
|
devi@23
|
46 sub process_command_lines;
|
devi@23
|
47 sub print_command_lines;
|
devi@23
|
48 sub printq;
|
devi@23
|
49
|
devi@25
|
50 sub save_cache_stat;
|
devi@25
|
51 sub load_cache_stat;
|
devi@27
|
52 sub print_session;
|
devi@25
|
53
|
devi@23
|
54 sub load_diff_files
|
devi@23
|
55 {
|
devi@23
|
56 my @pathes = @_;
|
devi@23
|
57
|
devi@23
|
58 for my $path (@pathes) {
|
devi@23
|
59 my $template = "*.diff";
|
devi@23
|
60 my @files = <$path/$template>;
|
devi@23
|
61 my $i=0;
|
devi@23
|
62 for my $file (@files) {
|
devi@28
|
63
|
devi@28
|
64 next if defined($Diffs{$file});
|
devi@28
|
65
|
devi@23
|
66 my %diff;
|
devi@23
|
67
|
devi@23
|
68 $diff{"path"}=$path;
|
devi@23
|
69 $diff{"uid"}="SET THIS";
|
devi@23
|
70
|
devi@23
|
71 # Сейчас UID определяется из названия каталога
|
devi@23
|
72 # откуда берутся diff-файлы
|
devi@23
|
73 # Это неправильно
|
devi@23
|
74 #
|
devi@23
|
75 # ВАРИАНТ:
|
devi@23
|
76 # К файлам жураналам должны прилагаться ситемны файлы,
|
devi@23
|
77 # мз которых и будет определяться соответствие
|
devi@23
|
78 # имён пользователей их uid'ам
|
devi@23
|
79 #
|
devi@23
|
80 $diff{"uid"} = 0 if $path =~ m@/root/@;
|
devi@23
|
81
|
devi@23
|
82 $diff{"bind_to"}="";
|
devi@23
|
83 $diff{"time_range"}=-1;
|
devi@23
|
84
|
devi@23
|
85 next if not $file=~m@/(D?[0-9][0-9]?[0-9]?)[^/]*?([0-9]*):([0-9]*):?([0-9]*)@;
|
devi@23
|
86 $diff{"day"}=$1 || "";
|
devi@23
|
87 $diff{"hour"}=$2;
|
devi@23
|
88 $diff{"min"}=$3;
|
devi@23
|
89 $diff{"sec"}=$4 || 0;
|
devi@23
|
90
|
devi@23
|
91 $diff{"index"}=$i;
|
devi@23
|
92
|
devi@23
|
93 print "diff loaded: $diff{day} $diff{hour}:$diff{min}:$diff{sec}\n";
|
devi@23
|
94
|
devi@23
|
95 local $/;
|
devi@23
|
96 open (F, "$file")
|
devi@23
|
97 or return "Can't open file $file ($_[0]) for reading";
|
devi@23
|
98 my $text = <F>;
|
devi@23
|
99 if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i) {
|
devi@23
|
100 my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8");
|
devi@23
|
101 $text = $converter->convert($text);
|
devi@23
|
102 }
|
devi@23
|
103 close(F);
|
devi@23
|
104 $diff{"text"}=$text;
|
devi@23
|
105 #print "$file loaded ($diff{day})\n";
|
devi@23
|
106
|
devi@28
|
107 #push @Diffs, \%diff;
|
devi@28
|
108 $Diffs{$file} = \%diff;
|
devi@23
|
109 $i++;
|
devi@23
|
110 }
|
devi@23
|
111 }
|
devi@23
|
112 }
|
devi@23
|
113
|
devi@23
|
114
|
devi@23
|
115 sub bind_diff
|
devi@23
|
116 {
|
devi@23
|
117 # my $path = shift;
|
devi@23
|
118 # my $pid = shift;
|
devi@23
|
119 # my $day = shift;
|
devi@23
|
120 # my $lab = shift;
|
devi@23
|
121
|
devi@23
|
122 print "Trying to bind diff...\n";
|
devi@23
|
123
|
devi@23
|
124 my $cl = shift;
|
devi@23
|
125 my $hour = $cl->{"hour"};
|
devi@23
|
126 my $min = $cl->{"min"};
|
devi@23
|
127 my $sec = $cl->{"sec"};
|
devi@23
|
128
|
devi@23
|
129 my $min_dt = 10000;
|
devi@23
|
130
|
devi@28
|
131 for my $diff_key (keys %Diffs) {
|
devi@28
|
132 my $diff = $Diffs{$diff_key};
|
devi@23
|
133 # Check here date, time and user
|
devi@23
|
134 next if ($diff->{"day"} && $cl->{"day"} && ($cl->{"day"} ne $diff->{"day"}));
|
devi@23
|
135 #next if (!$diff->{"uid"} && $cl->{"euid"} != $diff->{"uid"});
|
devi@23
|
136
|
devi@23
|
137 my $dt=($diff->{"hour"}-$hour)*3600 +($diff->{"min"}-$min)*60 + ($diff->{"sec"}-$sec);
|
devi@23
|
138 if ($dt >0 && $dt < $min_dt && ($diff->{"time_range"} <0 || $dt < $diff->{"time_range"})) {
|
devi@23
|
139 print "Approppriate diff found: dt=$dt\n";
|
devi@23
|
140 if ($diff->{"bind_to"}) {
|
devi@23
|
141 undef $diff->{"bind_to"}->{"diff"};
|
devi@23
|
142 };
|
devi@23
|
143 $diff->{"time_range"}=$dt;
|
devi@23
|
144 $diff->{"bind_to"}=$cl;
|
devi@23
|
145
|
devi@28
|
146 #$cl->{"diff"} = $diff->{"index"};
|
devi@28
|
147 $cl->{"diff"} = $diff_key;
|
devi@23
|
148 $min_dt = $dt;
|
devi@23
|
149 }
|
devi@23
|
150
|
devi@23
|
151 }
|
devi@23
|
152 }
|
devi@23
|
153
|
devi@23
|
154
|
devi@23
|
155 sub extract_from_cline
|
devi@23
|
156 # Разобрать командную строку $_[1] и возвратить хэш, содержащий
|
devi@23
|
157 # номер первого появление команды в строке:
|
devi@23
|
158 # команда => первая позиция
|
devi@23
|
159 {
|
devi@23
|
160 my $what = $_[0];
|
devi@23
|
161 my $cline = $_[1];
|
devi@23
|
162 my @lists = split /\;/, $cline;
|
devi@23
|
163
|
devi@23
|
164
|
devi@23
|
165 my @commands = ();
|
devi@23
|
166 for my $list (@lists) {
|
devi@23
|
167 push @commands, split /\|/, $list;
|
devi@23
|
168 }
|
devi@23
|
169
|
devi@23
|
170 my %commands;
|
devi@23
|
171 my %files;
|
devi@23
|
172 my $i=0;
|
devi@23
|
173 for my $command (@commands) {
|
devi@23
|
174 $command =~ /\s*(\S+)\s*(.*)/;
|
devi@23
|
175 if ($1 && $1 eq "sudo" ) {
|
devi@23
|
176 $commands{"$1"}=$i++;
|
devi@23
|
177 $command =~ s/\s*sudo\s+//;
|
devi@23
|
178 }
|
devi@23
|
179 $command =~ /\s*(\S+)\s*(.*)/;
|
devi@23
|
180 if ($1 && !defined $commands{"$1"}) {
|
devi@23
|
181 $commands{"$1"}=$i++;
|
devi@23
|
182 };
|
devi@23
|
183 if ($2) {
|
devi@23
|
184 my $args = $2;
|
devi@23
|
185 my @args = split (/\s+/, $args);
|
devi@23
|
186 for my $a (@args) {
|
devi@23
|
187 $files{"$a"}=$i++
|
devi@23
|
188 if !defined $files{"$a"};
|
devi@23
|
189 };
|
devi@23
|
190
|
devi@23
|
191
|
devi@23
|
192 }
|
devi@23
|
193 }
|
devi@23
|
194
|
devi@23
|
195 if ($what eq "commands") {
|
devi@23
|
196 return %commands;
|
devi@23
|
197 } else {
|
devi@23
|
198 return %files;
|
devi@23
|
199 }
|
devi@23
|
200
|
devi@23
|
201 }
|
devi@23
|
202
|
devi@23
|
203 sub load_command_lines
|
devi@23
|
204 {
|
devi@23
|
205 my $lab_scripts_path = $_[0];
|
devi@23
|
206 my $lab_scripts_mask = $_[1];
|
devi@23
|
207
|
devi@23
|
208 my $cline_re_base = qq'
|
devi@25
|
209 (
|
devi@25
|
210 (?:\\^?([0-9]*C?)) # exitcode
|
devi@23
|
211 (?:_([0-9]+)_)? # uid
|
devi@23
|
212 (?:_([0-9]+)_) # pid
|
devi@23
|
213 (...?) # day
|
devi@23
|
214 (.?.?) # lab
|
devi@23
|
215 \\s # space separator
|
devi@23
|
216 ([0-9][0-9]):([0-9][0-9]):([0-9][0-9]) # time
|
devi@23
|
217 .\\[50D.\\[K # killing symbols
|
devi@23
|
218 (.*?([\$\#]\\s?)) # prompt
|
devi@23
|
219 (.*) # command line
|
devi@25
|
220 )
|
devi@23
|
221 ';
|
devi@23
|
222 #my $cline_re = qr/$cline_re_base(?:$cline_re_base|$)/x;
|
devi@23
|
223 #my $cline_re = qr/(?:$cline_re_base)*$cline_re_base$/x;
|
devi@23
|
224 my $cline_re = qr/$cline_re_base/sx;
|
devi@23
|
225 my $cline_re1 = qr/$cline_re_base\x0D/sx;
|
devi@23
|
226 my $cline_re2 = qr/$cline_re_base$/sx;
|
devi@23
|
227
|
devi@23
|
228 my $vt = Term::VT102->new ( 'cols' => $Config{"terminal_width"},
|
devi@23
|
229 'rows' => $Config{"terminal_height"});
|
devi@23
|
230 my $cline_vt = Term::VT102->new ('cols' => $Config{"terminal_width"},
|
devi@23
|
231 'rows' => $Config{"terminal_height"});
|
devi@23
|
232
|
devi@23
|
233 my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8")
|
devi@23
|
234 if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i);
|
devi@23
|
235
|
devi@23
|
236 print "Loading lm-scripts...\n" if $Config{"verbose"} =~ /y/;
|
devi@23
|
237
|
devi@23
|
238 my $file;
|
devi@23
|
239 my $skip_info;
|
devi@23
|
240
|
devi@23
|
241 my $commandlines_loaded =0;
|
devi@23
|
242 my $commandlines_processed =0;
|
devi@23
|
243
|
devi@27
|
244 my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>;
|
devi@23
|
245 for $file (@lab_scripts){
|
devi@25
|
246
|
devi@25
|
247 # Пропускаем файл, если он не изменялся со времени нашего предудущего прохода
|
devi@25
|
248 my $size = (stat($file))[7];
|
devi@25
|
249 next if ($Script_Files{$file} && $Script_Files{$file}->{size} && $Script_Files{$file}->{size} >= $size);
|
devi@23
|
250
|
devi@27
|
251
|
devi@27
|
252 my $local_session_id;
|
devi@27
|
253 # Начальное значение идентификатора текущего сеанса определяем из имени скрипта
|
devi@27
|
254 # Впоследствии оно может быть уточнено
|
devi@30
|
255 $file =~ m@.*/([^/]*)\.script$@;
|
devi@27
|
256 $local_session_id = $1;
|
devi@27
|
257
|
devi@27
|
258 #Если файл только что появился,
|
devi@27
|
259 #пытаемся найти и загрузить информацию о соответствующей ему сессии
|
devi@27
|
260 if (!$Script_Files{$file}) {
|
devi@27
|
261 my $session_file = $file;
|
devi@27
|
262 $session_file =~ s/\.script/.info/;
|
devi@27
|
263 if (open(SESSION, $session_file)) {
|
devi@27
|
264 local $/;
|
devi@27
|
265 my $data = <SESSION>;
|
devi@27
|
266 close(SESSION);
|
devi@27
|
267
|
devi@27
|
268 for my $session_data ($data =~ m@<session>(.*?)</session>@sg) {
|
devi@27
|
269 my %session;
|
devi@27
|
270 while ($session_data =~ m@<([^>]*?)>(.*?)</\1>@sg) {
|
devi@27
|
271 $session{$1} = $2;
|
devi@27
|
272 }
|
devi@27
|
273 $local_session_id = $session{"local_session_id"} if $session{"local_session_id"};
|
devi@28
|
274 $Sessions{$local_session_id}=\%session;
|
devi@27
|
275 }
|
devi@27
|
276
|
devi@27
|
277 #Загруженную информацию сразу же отправляем в поток
|
devi@27
|
278 print_session($Config{cache}, $local_session_id);
|
devi@27
|
279 }
|
devi@27
|
280 }
|
devi@27
|
281
|
devi@23
|
282 open (FILE, "$file");
|
devi@23
|
283 binmode FILE;
|
devi@25
|
284
|
devi@25
|
285 # Переходим к тому месту, где мы окончили разбор
|
devi@25
|
286 seek (FILE, $Script_Files{$file}->{tell}, 0) if $Script_Files{$file}->{tell};
|
devi@25
|
287 $Script_Files{$file}->{size} = $size;
|
devi@25
|
288 $Script_Files{$file}->{tell} = 0 unless $Script_Files{$file}->{tell};
|
devi@25
|
289
|
|