lilalo

annotate l3-agent @ 100:2c00c61f2d7b

Коммичу изменения, но сам не знаю зачем.
Нужно l3-cgi переписать вообще с нуля.
Он мерзкий.

И продумать нужно, как он вообще должен работать.
Понятно, приблизительно, как он должен показывать журнал,
когда до него уже дошли,
но вот если не дошли, то что делать не понятно.
Короче, продумать систему навигации.
author devi
date Wed Jun 14 21:37:22 2006 +0300 (2006-06-14)
parents 3058ada85a58
children 0d49f33696b3
rev   line source
devi@52 1 #!/usr/bin/perl -w
devi@23 2
devi@23 3 #
devi@62 4 # (c) Igor Chubin, igor@chub.in, 2004-2006
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@62 27 our %Script_Files; # Информация о позициях в скрипт-файлах,
devi@62 28 # до которых уже выполнен разбор
devi@62 29 # и информация о времени модификации файла
devi@62 30 # $Script_Files{$file}->{size}
devi@62 31 # $Script_Files{$file}->{tell}
devi@23 32
devi@62 33 our $Killed =0; # В режиме демона -- процесс получил сигнал о завершении
devi@23 34
devi@23 35 sub init_variables;
devi@23 36 sub main;
devi@23 37
devi@23 38 sub load_diff_files;
devi@23 39 sub bind_diff;
devi@62 40 sub extract_commands_from_cline;
devi@23 41 sub load_command_lines;
devi@23 42 sub sort_command_lines;
devi@23 43 sub print_command_lines;
devi@23 44 sub printq;
devi@23 45
devi@25 46 sub save_cache_stat;
devi@25 47 sub load_cache_stat;
devi@27 48 sub print_session;
devi@25 49
devi@23 50 sub load_diff_files
devi@23 51 {
devi@62 52 my @pathes = @_;
devi@62 53
devi@62 54 for my $path (@pathes) {
devi@62 55 my $template = "*.diff";
devi@62 56 my @files = <$path/$template>;
devi@62 57 my $i=0;
devi@62 58 for my $file (@files) {
devi@28 59
devi@62 60 next if defined($Diffs{$file});
devi@62 61 my %diff;
devi@23 62
devi@80 63 # Старый формат имени diff-файла
devi@80 64 # DEPRECATED
devi@80 65 if ($file=~m@/(D?[0-9][0-9]?[0-9]?)[^/]*?([0-9]*):([0-9]*):?([0-9]*)@) {
devi@80 66 $diff{"day"}=$1 || "";
devi@80 67 $diff{"hour"}=$2;
devi@80 68 $diff{"min"}=$3;
devi@80 69 $diff{"sec"}=$4 || 0;
devi@80 70
devi@80 71 $diff{"uid"} = 0 if $path =~ m@/root/@;
devi@23 72
devi@62 73 print "diff loaded: $diff{day} $diff{hour}:$diff{min}:$diff{sec}\n";
devi@80 74
devi@80 75 }
devi@80 76 # Новый формат имени diff-файла
devi@80 77 elsif ($file =~ m@.*/([^_]*)_([0-9]+)(.*)@) {
devi@80 78 $diff{"local_session_id"} = $1;
devi@80 79 $diff{"time"} = $2;
devi@80 80 $diff{"filename"} = $3;
devi@80 81 $diff{"filename"} =~ s@_@/@g;
devi@80 82 $diff{"filename"} =~ s@//@_@g;
devi@80 83
devi@80 84 print "diff loaded: $diff{filename} (time=$diff{time},session=$diff{local_session_id})\n";
devi@80 85 }
devi@80 86 else {
devi@80 87 next;
devi@80 88 }
devi@80 89
devi@80 90 # Чтение и изменение кодировки содержимого diff-файла
devi@62 91 local $/;
devi@62 92 open (F, "$file")
devi@62 93 or return "Can't open file $file ($_[0]) for reading";
devi@62 94 my $text = <F>;
devi@62 95 if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i) {
devi@62 96 my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8");
devi@62 97 $text = $converter->convert($text);
devi@62 98 }
devi@62 99 close(F);
devi@62 100 $diff{"text"}=$text;
devi@23 101
devi@80 102 $diff{"path"}=$path;
devi@80 103 $diff{"bind_to"}="";
devi@80 104 $diff{"time_range"}=-1;
devi@80 105 $diff{"index"}=$i;
devi@80 106
devi@62 107 $Diffs{$file} = \%diff;
devi@62 108 $i++;
devi@62 109 }
devi@62 110 }
devi@23 111 }
devi@23 112
devi@23 113
devi@23 114 sub bind_diff
devi@23 115 {
devi@62 116 print "Trying to bind diff...\n";
devi@23 117
devi@62 118 my $cl = shift;
devi@62 119 my $hour = $cl->{"hour"};
devi@62 120 my $min = $cl->{"min"};
devi@62 121 my $sec = $cl->{"sec"};
devi@23 122
devi@62 123 my $min_dt = 10000;
devi@23 124
devi@62 125 for my $diff_key (keys %Diffs) {
devi@62 126 my $diff = $Diffs{$diff_key};
devi@80 127 next if ($diff->{"local_session_id"}
devi@80 128 && $cl->{"local_session_id"}
devi@80 129 && ($cl->{"local_session_id"} ne $diff->{"local_session_id"}));
devi@80 130
devi@62 131 next if ($diff->{"day"} && $cl->{"day"} && ($cl->{"day"} ne $diff->{"day"}));
devi@80 132
devi@80 133 my $dt;
devi@80 134 if ($diff->{"time"} && $cl->{"time"}) {
devi@80 135 $dt = $diff->{"time"} - $cl->{"time"}
devi@80 136 }
devi@80 137 else {
devi@80 138 $dt=($diff->{"hour"}-$hour)*3600 +($diff->{"min"}-$min)*60 + ($diff->{"sec"}-$sec);
devi@80 139 }
devi@80 140 if ($dt >0
devi@80 141 && $dt < $min_dt
devi@80 142 && ($diff->{"time_range"} <0
devi@80 143 || $dt < $diff->{"time_range"})) {
devi@62 144 print "Approppriate diff found: dt=$dt\n";
devi@62 145 if ($diff->{"bind_to"}) {
devi@62 146 undef $diff->{"bind_to"}->{"diff"};
devi@62 147 };
devi@62 148 $diff->{"time_range"}=$dt;
devi@62 149 $diff->{"bind_to"}=$cl;
devi@23 150
devi@62 151 $cl->{"diff"} = $diff_key;
devi@62 152 $min_dt = $dt;
devi@80 153 }
devi@62 154 }
devi@23 155 }
devi@23 156
devi@23 157
devi@62 158 sub extract_commands_from_cline
devi@23 159 # Разобрать командную строку $_[1] и возвратить хэш, содержащий
devi@23 160 # номер первого появление команды в строке:
devi@62 161 # команда => первая позиция
devi@23 162 {
devi@62 163 my $cline = $_[0];
devi@62 164 my @lists = split /\;/, $cline;
devi@62 165
devi@62 166
devi@62 167 my @commands = ();
devi@62 168 for my $list (@lists) {
devi@62 169 push @commands, split /\|/, $list;
devi@62 170 }
devi@23 171
devi@62 172 my %commands;
devi@62 173 my %files;
devi@62 174 my $i=0;
devi@62 175 for my $command (@commands) {
devi@62 176 $command =~ /\s*(\S+)\s*(.*)/;
devi@62 177 if ($1 && $1 eq "sudo" ) {
devi@62 178 $commands{"$1"}=$i++;
devi@62 179 $command =~ s/\s*sudo\s+//;
devi@62 180 }
devi@62 181 $command =~ /\s*(\S+)\s*(.*)/;
devi@62 182 if ($1 && !defined $commands{"$1"}) {
devi@62 183 $commands{"$1"}=$i++;
devi@62 184 };
devi@62 185 }
devi@62 186 return %commands;
devi@23 187 }
devi@23 188
devi@23 189 sub load_command_lines
devi@23 190 {
devi@62 191 my $lab_scripts_path = $_[0];
devi@62 192 my $lab_scripts_mask = $_[1];
devi@23 193
devi@62 194 my $cline_re_base = qq'
devi@62 195 (
devi@62 196 (?:\\^?([0-9]*C?)) # exitcode
devi@62 197 (?:_([0-9]+)_)? # uid
devi@62 198 (?:_([0-9]+)_) # pid
devi@62 199 (...?) # day
devi@62 200 (.?.?) # lab
devi@62 201 \\s # space separator
devi@62 202 ([0-9][0-9]):([0-9][0-9]):([0-9][0-9]) # time
devi@62 203 .\\[50D.\\[K # killing symbols
devi@62 204 (.*?([\$\#]\\s?)) # prompt
devi@62 205 (.*) # command line
devi@62 206 )
devi@62 207 ';
devi@62 208 my $cline_re = qr/$cline_re_base/sx;
devi@62 209 my $cline_re2 = qr/$cline_re_base$/sx;
devi@23 210
devi@74 211 my $cline_re_v2_base = qq'
devi@74 212 (
devi@74 213 v2[\#] # version
devi@74 214 ([0-9]+)[\#] # history line number
devi@74 215 ([0-9]+)[\#] # exitcode
devi@74 216 ([0-9]+)[\#] # uid
devi@74 217 ([0-9]+)[\#] # pid
devi@74 218 ([0-9]+)[\#] # time
devi@74 219 (.*?)[\#] # pwd
devi@74 220 .\\[1024D.\\[K # killing symbols
devi@74 221 (.*?([\$\#]\\s?)) # prompt
devi@74 222 (.*) # command line
devi@74 223 )
devi@74 224 ';
devi@74 225
devi@74 226 my $cline_re_v2 = qr/$cline_re_v2_base/sx;
devi@74 227 my $cline_re2_v2 = qr/$cline_re_v2_base$/sx;
devi@74 228
devi@62 229 my $vt = Term::VT102->new ( 'cols' => $Config{"terminal_width"},
devi@81 230 'rows' => $Config{"terminal_height"});
devi@81 231 my $cline_vt = Term::VT102->new (
devi@81 232 'cols' => $Config{"terminal_width"},
devi@81 233 'rows' => $Config{"terminal_height"});
devi@23 234
devi@62 235 my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8")
devi@62 236 if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i);
devi@62 237
devi@74 238 print "Parsing lab scripts...\n" if $Config{"verbose"} =~ /y/;
devi@23 239
devi@62 240 my $file;
devi@62 241 my $skip_info;
devi@23 242
devi@62 243 my $commandlines_loaded =0;
devi@62 244 my $commandlines_processed =0;
devi@23 245
devi@62 246 my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>;
devi@62 247 for $file (@lab_scripts){
devi@23 248
devi@62 249 # Пропускаем файл, если он не изменялся со времени нашего предудущего прохода
devi@62 250 my $size = (stat($file))[7];
devi@62 251 next if ($Script_Files{$file} && $Script_Files{$file}->{size} && $Script_Files{$file}->{size} >= $size);
devi@27 252
devi@27 253
devi@62 254 my $local_session_id;
devi@62 255 # Начальное значение идентификатора текущего сеанса определяем из имени скрипта
devi@62 256 # Впоследствии оно может быть уточнено
devi@62 257 $file =~ m@.*/([^/]*)\.script$@;
devi@62 258 $local_session_id = $1;
devi@27 259
devi@62 260 #Если файл только что появился,
devi@62 261 #пытаемся найти и загрузить информацию о соответствующей ему сессии
devi@62 262 if (!$Script_Files{$file}) {
devi@62 263 my $session_file = $file;
devi@62 264 $session_file =~ s/\.script/.info/;
devi@62 265 if (open(SESSION, $session_file)) {
devi@62 266 local $/;
devi@62 267 my $data = <SESSION>;
devi@62 268 close(SESSION);
devi@27 269
devi@62 270 for my $session_data ($data =~ m@<session>(.*?)</session>@sg) {
devi@62 271 my %session;
devi@62 272 while ($session_data =~ m@<([^>]*?)>(.*?)</\1>@sg) {
devi@62 273 $session{$1} = $2;
devi@62 274 }
devi@62 275 $local_session_id = $session{"local_session_id"} if $session{"local_session_id"};
devi@62 276 $Sessions{$local_session_id}=\%session;
devi@62 277 }
devi@25 278
devi@62 279 #Загруженную информацию сразу же отправляем в поток
devi@62 280 print_session($Config{cache}, $local_session_id);
devi@62 281 }
devi@84 282 else {
devi@84 283 die "can't open session file";
devi@84 284 }
devi@62 285 }
devi@25 286
devi@62 287 open (FILE, "$file");
devi@62 288 binmode FILE;
devi@23 289
devi@62 290 # Переходим к тому месту, где мы окончили разбор
devi@62 291 seek (FILE, $Script_Files{$file}->{tell}, 0) if $Script_Files{$file}->{tell};
devi@62 292 $Script_Files{$file}->{size} = $size;
devi@62 293 $Script_Files{$file}->{tell} = 0 unless $Script_Files{$file}->{tell};
devi@32 294
devi@62 295 $file =~ m@.*/(.*?)-.*@;
devi@23 296
devi@83 297 print "\n+- processing file $file\n| "
devi@83 298 if $Config{"verbose"} =~/y/;
devi@74 299
devi@62 300 my $tty = $1;
devi@62 301 my $first_pass = 1;
devi@62 302 my %cl;
devi@62 303 my $last_output_length=0;
devi@62 304 while (<FILE>) {
devi@62 305 $commandlines_processed++;
devi@23 306
devi@62 307 next if s/^Script started on.*?\n//s;
devi@23 308
devi@62 309 if (/[0-9][0-9]:[0-9][0-9]:[0-9][0-9].\[[0-9][0-9]D.\[K/ && m/$cline_re/) {
devi@62 310 s/.*\x0d(?!\x0a)//;
devi@62 311 m/$cline_re2/gs;
devi@23 312
devi@62 313 $commandlines_loaded++;
devi@62 314 $last_output_length=0;
devi@23 315
devi@62 316 # Previous command
devi@62 317 my %last_cl = %cl;
devi@62 318 my $err = $2 || "";
devi@23 319
devi@62 320 $cl{"local_session_id"} = $local_session_id;
devi@62 321 # Parse new command
devi@62 322 $cl{"uid"} = $3;
devi@74 323 #$cl{"euid"} = $cl{"uid"}; # Если в команде обнаружится sudo, euid поменяем на 0
devi@62 324 $cl{"pid"} = $4;
devi@62 325 $cl{"day"} = $5;
devi@62 326 $cl{"lab"} = $6;
devi@62 327 $cl{"hour"} = $7;
devi@62 328 $cl{"min"} = $8;
devi@62 329 $cl{"sec"} = $9;
devi@72 330 #$cl{"fullprompt"} = $10;
devi@62 331 $cl{"prompt"} = $11;
devi@62 332 $cl{"raw_cline"} = $12;
devi@23 333
devi@62 334 {
devi@62 335 use bytes;
devi@62 336 $cl{"raw_start"} = tell (FILE) - length($1);
devi@62 337 $cl{"raw_output_start"} = tell FILE;
devi@62 338 }
devi@62 339 $cl{"raw_file"} = $file;
devi@23 340
devi@62 341 $cl{"err"} = 0;
devi@62 342 $cl{"output"} = "";
devi@62 343 $cl{"tty"} = $tty;
devi@23 344
devi@62 345 $cline_vt->process($cl{"raw_cline"}."\n");
devi@62 346 $cl{"cline"} = $cline_vt->row_plaintext (1);
devi@62 347 $cl{"cline"} =~ s/\s*$//;
devi@62 348 $cline_vt->reset();
devi@23 349
devi@62 350 my %commands = extract_commands_from_cline($cl{"cline"});
devi@74 351 #$cl{"euid"}=0 if defined $commands{"sudo"};
devi@62 352 my @comms = sort { $commands{$a} cmp $commands{$b} } keys %commands;
devi@62 353 $cl{"last_command"} = $comms[$#comms] || "";
devi@23 354
devi@62 355 if (
devi@62 356 $Config{"suppress_editors"} =~ /^y/i
devi@62 357 && grep ($_ eq $cl{"last_command"}, @{$Config{"editors"}})
devi@62 358 || $Config{"suppress_pagers"} =~ /^y/i
devi@62 359 && grep ($_ eq $cl{"last_command"}, @{$Config{"pagers"}})
devi@62 360 || $Config{"suppress_terminal"}=~ /^y/i
devi@62 361 && grep ($_ eq $cl{"last_command"}, @{$Config{"terminal"}})
devi@62 362 ) {
devi@62 363 $cl{"suppress_output"} = "1";
devi@62 364 }
devi@62 365 else {
devi@62 366 $cl{"suppress_output"} = "0";
devi@62 367 }
devi@62 368 $skip_info = 0;
devi@23 369
devi@23 370
devi@62 371 print " ",$cl{"last_command"};
devi@23 372
devi@62 373 # Processing previous command line
devi@62 374 if ($first_pass) {
devi@62 375 $first_pass = 0;
devi@62 376 next;
devi@62 377 }
devi@23 378
devi@62 379 # Error code
devi@62 380 $last_cl{"raw_end"} = $cl{"raw_start"};
devi@62 381 $last_cl{"err"}=$err;
devi@62 382 $last_cl{"err"}=130 if $err eq "^C";
devi@23 383
devi@62 384 if (grep ($_ eq $last_cl{"last_command"}, @{$Config{"editors"}})) {
devi@62 385 bind_diff(\%last_cl);
devi@62 386 }
devi@23 387
devi@62 388 # Output
devi@62 389 if (!$last_cl{"suppress_output"} || $last_cl{"err"}) {
devi@62 390 for (my $i=0; $i<$Config{"terminal_height"}; $i++) {
devi@62 391 my $line= $vt->row_plaintext($i);
devi@62 392 next if !defined ($line) ; #|| $line =~ /^\s*$/;
devi@62 393 $line =~ s/\s*$//;
devi@62 394 $line .= "\n" unless $line =~ /^\s*$/;
devi@62 395 $last_cl{"output"} .= $line;
devi@62 396 }
devi@62 397 }
devi@62 398 else {
devi@62 399 $last_cl{"output"}= "";
devi@62 400 }
devi@23 401
devi@62 402 $vt->reset();
devi@23 403
devi@23 404
devi@62 405 # Save
devi@62 406 if (!$Config{"lab"} || $cl{"lab"} eq $Config{"lab"}) {
devi@62 407 # Changing encoding
devi@62 408 for (keys %last_cl) {
devi@62 409 next if /raw/;
devi@62 410 $last_cl{$_} = $converter->convert($last_cl{$_})
devi@62 411 if ($Config{"encoding"} &&
devi@62 412 $Config{"encoding"} !~ /^utf-8$/i);
devi@62 413 }
devi@62 414 push @Command_Lines, \%last_cl;
devi@23 415
devi@62 416 # Сохранение позиции в файле, до которой выполнен
devi@62 417 # успешный разбор
devi@62 418 $Script_Files{$file}->{tell} = $last_cl{raw_end};
devi@62 419 }
devi@62 420 next;
devi@62 421 }
devi@74 422
devi@74 423
devi@74 424 elsif (m/$cline_re_v2/) {
devi@74 425
devi@74 426
devi@74 427 # Разбираем командную строку версии 2
devi@74 428
devi@74 429
devi@74 430 s/.*\x0d(?!\x0a)//;
devi@74 431 m/$cline_re2_v2/gs;
devi@74 432
devi@74 433 $commandlines_loaded++;
devi@74 434 $last_output_length=0;
devi@74 435
devi@74 436 # Previous command
devi@74 437 my %last_cl = %cl;
devi@74 438
devi@74 439 $cl{"local_session_id"} = $local_session_id;
devi@74 440 # Parse new command
devi@74 441 $cl{"history"} = $2;
devi@74 442 my $err = $3;
devi@74 443 $cl{"uid"} = $4;
devi@74 444 #$cl{"euid"} = $cl{"uid"}; # Если в команде обнаружится sudo, euid поменяем на 0
devi@74 445 $cl{"pid"} = $5;
devi@74 446 $cl{"time"} = $6;
devi@74 447 $cl{"pwd"} = $7;
devi@74 448 #$cl{"fullprompt"} = $8;
devi@74 449 $cl{"prompt"} = $9;
devi@74 450 $cl{"raw_cline"}= $10;
devi@74 451
devi@74 452 {
devi@74 453 use bytes;
devi@74 454 $cl{"raw_start"} = tell (FILE) - length($1);
devi@74 455 $cl{"raw_output_start"} = tell FILE;
devi@74 456 }
devi@74 457 $cl{"raw_file"} = $file;
devi@74 458
devi@74 459 $cl{"err"} = 0;
devi@74 460 $cl{"output"} = "";
devi@74 461 #$cl{"tty"} = $tty;
devi@74 462
devi@74 463 $cline_vt->process($cl{"raw_cline"}."\n");
devi@74 464 $cl{"cline"} = $cline_vt->row_plaintext (1);
devi@74 465 $cl{"cline"} =~ s/\s*$//;
devi@74 466 $cline_vt->reset();
devi@74 467
devi@74 468 my %commands = extract_commands_from_cline($cl{"cline"});
devi@74 469 #$cl{"euid"} = 0 if defined $commands{"sudo"};
devi@74 470 my @comms = sort { $commands{$a} cmp $commands{$b} } keys %commands;
devi@74 471 $cl{"last_command"}
devi@74 472 = $comms[$#comms] || "";
devi@74 473
devi@74 474 if (
devi@74 475 $Config{"suppress_editors"} =~ /^y/i
devi@74 476 && grep ($_ eq $cl{"last_command"}, @{$Config{"editors"}})
devi@74 477 || $Config{"suppress_pagers"} =~ /^y/i
devi@74 478 && grep ($_ eq $cl{"last_command"}, @{$Config{"pagers"}})
devi@74 479 || $Config{"suppress_terminal"}=~ /^y/i
devi@74 480 && grep ($_ eq $cl{"last_command"}, @{$Config{"terminal"}})
devi@74 481 ) {
devi@74 482 $cl{"suppress_output"} = "1";
devi@74 483 }
devi@74 484 else {
devi@74 485 $cl{"suppress_output"} = "0";
devi@74 486 }
devi@74 487 $skip_info = 0;
devi@74 488
devi@74 489
devi@74 490 if ($Config{verbose} =~ /y/i) {
devi@83 491 print "\n| " if $commandlines_loaded % 5 == 1;
devi@74 492 print " ",$cl{"last_command"};
devi@74 493 }
devi@74 494
devi@74 495 # Processing previous command line
devi@74 496 if ($first_pass) {
devi@74 497 $first_pass = 0;
devi@74 498 next;
devi@74 499 }
devi@74 500
devi@74 501 # Error code
devi@74 502 $last_cl{"err"}=$err;
devi@74 503 $last_cl{"raw_end"} = $cl{"raw_start"};
devi@74 504
devi@74 505 if (grep ($_ eq $last_cl{"last_command"}, @{$Config{"editors"}})) {
devi@74 506 bind_diff(\%last_cl);
devi@74 507 }
devi@74 508
devi@74 509 # Output
devi@74 510 if (!$last_cl{"suppress_output"} || $last_cl{"err"}) {
devi@74 511 for (my $i=0; $i<$Config{"terminal_height"}; $i++) {
devi@74 512 my $line= $vt->row_plaintext($i);
devi@74 513 next if !defined ($line) ; #|| $line =~ /^\s*$/;
devi@74 514 $line =~ s/\s*$//;
devi@74 515 $line .= "\n" unless $line =~ /^\s*$/;
devi@74 516 $last_cl{"output"} .= $line;
devi@74 517 }
devi@74 518 }
devi@74 519 else {
devi@74 520 $last_cl{"output"}= "";
devi@74 521 }
devi@74 522
devi@74 523 $vt->reset();
devi@74 524
devi@74 525
devi@74 526 # Changing encoding
devi@74 527 for (keys %last_cl) {
devi@74 528 next if /raw/;
devi@74 529 if ($Config{"encoding"} &&
devi@74 530 $Config{"encoding"} !~ /^utf-8$/i) {
devi@74 531 $last_cl{$_} = $converter->convert($last_cl{$_})
devi@74 532 }
devi@74 533 }
devi@74 534 push @Command_Lines, \%last_cl;
devi@74 535
devi@74 536 # Сохранение позиции в файле, до которой выполнен
devi@74 537 # успешный разбор
devi@74 538 $Script_Files{$file}->{tell} = $last_cl{raw_end};
devi@74 539
devi@74 540 next;
devi@74 541
devi@74 542 }
devi@74 543
devi@74 544 # Иначе, это строка вывода
devi@74 545
devi@62 546 $last_output_length+=length($_);
devi@62 547 #if (!$cl{"suppress_output"} || $last_output_length < 5000) {
devi@62 548 if ($last_output_length < 50000) {
devi@62 549 $vt->process("$_"."\n")
devi@62 550 }
devi@62 551 else
devi@62 552 {
devi@62 553 if (!$skip_info) {
devi@62 554 print "($cl{last_command})";
devi@62 555 $skip_info = 1;
devi@62 556 }
devi@62 557 }
devi@62 558 }
devi@62 559 close(FILE);
devi@23 560
devi@62 561 }
devi@62 562 if ($Config{"verbose"} =~ /y/) {
devi@74 563 print "\n`- finished.\n" ;
devi@62 564 print "Lines loaded: $commandlines_processed\n";
devi@62 565 print "Command lines: $commandlines_loaded\n";
devi@62 566 }
devi@23 567 }
devi@23 568
devi@23 569
devi@23 570
devi@62 571
devi@62 572 sub sort_command_lines
devi@62 573 {
devi@74 574 print "Sorting command lines..." if $Config{"verbose"} =~ /y/;
devi@62 575
devi@62 576 # Sort Command_Lines
devi@62 577 # Write Command_Lines to Command_Lines_Index
devi@62 578
devi@62 579 my @index;
devi@62 580 for (my $i=0;$i<=$#Command_Lines;$i++) {
devi@62 581 $index[$i]=$i;
devi@62 582 }
devi@62 583
devi@62 584 @Command_Lines_Index = sort {
devi@86 585 defined($Command_Lines[$index[$a]]->{"time"})
devi@86 586 && defined($Command_Lines[$index[$b]]->{"time"})
devi@81 587 ? $Command_Lines[$index[$a]]->{"time"} <=> $Command_Lines[$index[$b]]->{"time"}
devi@84 588 : defined($Command_Lines[$index[$a]]->{"day"})
devi@86 589 && defined($Command_Lines[$index[$b]]->{"day"})
devi@86 590 && defined($Command_Lines[$index[$a]]->{"hour"})
devi@86 591 && defined($Command_Lines[$index[$b]]->{"hour"})
devi@86 592 && defined($Command_Lines[$index[$a]]->{"min"})
devi@86 593 && defined($Command_Lines[$index[$b]]->{"min"})
devi@86 594 && defined($Command_Lines[$index[$a]]->{"sec"})
devi@86 595 && defined($Command_Lines[$index[$b]]->{"sec"})
devi@86 596 ? $Command_Lines[$index[$a]]->{"day"} cmp $Command_Lines[$index[$b]]->{"day"}
devi@86 597 || $Command_Lines[$index[$a]]->{"hour"} <=> $Command_Lines[$index[$b]]->{"hour"}
devi@86 598 || $Command_Lines[$index[$a]]->{"min"} <=> $Command_Lines[$index[$b]]->{"min"}
devi@86 599 || $Command_Lines[$index[$a]]->{"sec"} <=> $Command_Lines[$index[$b]]->{"sec"}
devi@86 600 : 0
devi@62 601 } @index;
devi@62 602
devi@74 603 print "finished\n" if $Config{"verbose"} =~ /y/;
devi@62 604
devi@62 605 }
devi@62 606
devi@23 607 sub printq
devi@23 608 {
devi@62 609 my $TO = shift;
devi@62 610 my $text = join "", @_;
devi@62 611 $text =~ s/&/&amp;/g;
devi@62 612 $text =~ s/</&lt;/g;
devi@62 613 $text =~ s/>/&gt;/g;
devi@62 614 print $TO $text;
devi@23 615 }
devi@23 616
devi@23 617
devi@23 618 =cut
devi@23 619 Вывести результат обработки журнала.
devi@23 620 =cut
devi@23 621
devi@23 622 sub print_command_lines
devi@23 623 {
devi@62 624 my $output_filename=$_[0];
devi@85 625 open(OUT, ">>", $output_filename)
devi@62 626 or die "Can't open $output_filename for writing\n";
devi@23 627
devi@23 628
devi@62 629 my $cl;
devi@62 630 my $in_range=0;
devi@62 631 for my $i (@Command_Lines_Index) {
devi@62 632 $cl = $Command_Lines[$i];
devi@23 633
devi@62 634 if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) {
devi@62 635 $in_range=1;
devi@62 636 next;
devi@62 637 }
devi@62 638 if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) {
devi@62 639 $in_range=0;
devi@62 640 next;
devi@62 641 }
devi@62 642 next if ($Config{"from"} && $Config{"to"} && !$in_range)
devi@62 643 ||
devi@62 644 ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ )
devi@62 645 ||
devi@62 646 ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0)
devi@62 647 ||
devi@62 648 ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
devi@62 649
devi@62 650 # Вырезаем из вывода только нужное количество строк
devi@23 651
devi@62 652 my $output="";
devi@69 653
devi@73 654 if (!grep ($_ eq $cl->{"last_command"}, @{$Config{"full_output_commands"}})
devi@69 655 && ($Config{"head_lines"}
devi@73 656 || $Config{"tail_lines"})) {
devi@62 657 # Partialy output
devi@62 658 my @lines = split '\n', $cl->{"output"};
devi@62 659 # head
devi@62 660 my $mark=1;
devi@62 661 for (my $i=0; $i<= $#lines && $i < $Config{"cache_head_lines"}; $i++) {
devi@62 662 $output .= $lines[$i]."\n";
devi@62 663 }
devi@62 664 # tail
devi@62 665 my $start=$#lines-$Config{"cache_tail_lines"}+1;
devi@62 666 if ($start < 0) {
devi@62 667 $start=0;
devi@62 668 $mark=0;
devi@62 669 }
devi@62 670 if ($start < $Config{"cache_head_lines"}) {
devi@62 671 $start=$Config{"cache_head_lines"};
devi@62 672 $mark=0;
devi@62 673 }
devi@62 674 $output .= $Config{"skip_text"}."\n" if $mark;
devi@73 675 for ($i=$start; $i<= $#lines; $i++) {
devi@62 676 $output .= $lines[$i]."\n";
devi@62 677 }
devi@62 678 }
devi@62 679 else {
devi@62 680 # Full output
devi@62 681 $output .= $cl->{"output"};
devi@62 682 }
devi@23 683
devi@62 684 # Совместимость с labmaker
devi@23 685
devi@62 686 # Переводим в секунды Эпохи
devi@62 687 # В labmaker'е данные хранились в неудобной форме: hour, min, sec, day of year
devi@62 688 # Информация о годе отсутствовала
devi@62 689 # Её можно внести:
devi@62 690 # Декабрь 2004 год; остальные -- 2005 год.
devi@23 691
devi@62 692 my $year = 2005;
devi@62 693 #$year = 2004 if ( $cl->{day} > 330 );
devi@62 694 $year = $Config{year} if $Config{year};
devi@62 695 # timelocal( $sec, $min, $hour, $mday,$mon,$year);
devi@74 696 $cl->{time} ||= timelocal_nocheck($cl->{sec},$cl->{min},$cl->{hour},$cl->{day},0,$year);
devi@23 697
devi@23 698
devi@62 699 # Начинаем вывод команды
devi@62 700 print OUT "<command>\n";
devi@98 701 print OUT "<l3cd>$Config{l3cd}</l3cd>\n" if $Config{"l3cd"};
devi@62 702 for my $element (qw(
devi@62 703 local_session_id
devi@74 704 history
devi@74 705 uid
devi@74 706 pid
devi@62 707 time
devi@74 708 pwd
devi@62 709 raw_start
devi@62 710 raw_output_start
devi@62 711 raw_end
devi@62 712 raw_file
devi@62 713 tty
devi@62 714 err
devi@62 715 last_command
devi@74 716 history
devi@62 717 )) {
devi@65 718 next unless defined($cl->{"$element"});
devi@62 719 print OUT "<$element>".$cl->{$element}."</$element>\n";
devi@62 720 }
devi@62 721 for my $element (qw(
devi@62 722 prompt
devi@62 723 cline
devi@62 724 )) {
devi@65 725 next unless defined($cl->{"$element"});
devi@62 726 print OUT "<$element>";
devi@62 727 printq(\*OUT,$cl->{"$element"});
devi@62 728 print OUT "</$element>\n";
devi@62 729 }
devi@72 730 #note
devi@72 731 #note_title
devi@62 732 print OUT "<output>";
devi@62 733 printq(\*OUT,$output);
devi@62 734 print OUT "</output>\n";
devi@62 735 if ($cl->{"diff"}) {
devi@62 736 print OUT "<diff>";
devi@62 737 printq(\*OUT,${$Diffs{$cl->{"diff"}}}{"text"});
devi@62 738 print OUT "</diff>\n";
devi@62 739 }
devi@62 740 print OUT "</command>\n";
devi@23 741
devi@62 742 }
devi@23 743
devi@62 744 close(OUT);
devi@27 745 }
devi@27 746
devi@27 747 sub print_session
devi@27 748 {
devi@62 749 my $output_filename = $_[0];
devi@62 750 my $local_session_id = $_[1];
devi@62 751 return if not defined($Sessions{$local_session_id});
devi@27 752
devi@84 753 print "printing session info. session id = ".$local_session_id."\n"
devi@84 754 if $Config{verbose} =~ /y/;
devi@84 755
devi@62 756 open(OUT, ">>", $output_filename)
devi@62 757 or die "Can't open $output_filename for writing\n";
devi@62 758 print OUT "<session>\n";
devi@98 759 print OUT "<l3cd>$Config{l3cd}</l3cd>\n" if $Config{"l3cd"};
devi@62 760 my %session = %{$Sessions{$local_session_id}};
devi@62 761 for my $key (keys %session) {
devi@84 762 print OUT "<$key>".$session{$key}."</$key>\n";
devi@84 763 print " ".$key,"\n";
devi@62 764 }
devi@62 765 print OUT "</session>\n";
devi@62 766 close(OUT);
devi@27 767 }
devi@27 768
devi@27 769 sub send_cache
devi@27 770 {
devi@62 771 # Если в кэше что-то накопилось,
devi@62 772 # попытаемся отправить это на сервер
devi@62 773 #
devi@62 774 my $cache_was_sent=0;
devi@62 775
devi@62 776 if (open(CACHE, $Config{cache})) {
devi@62 777 local $/;
devi@62 778 my $cache = <CACHE>;
devi@62 779 close(CACHE);
devi@27 780
devi@62 781 my $socket = IO::Socket::INET->new(
devi@62 782 PeerAddr => $Config{backend_address},
devi@62 783 PeerPort => $Config{backend_port},
devi@62 784 proto => "tcp",
devi@62 785 Type => SOCK_STREAM
devi@62 786 );
devi@27 787
devi@62 788 if ($socket) {
devi@62 789 print $socket $cache;
devi@62 790 close($socket);
devi@62 791 $cache_was_sent = 1;
devi@62 792 }
devi@62 793 }
devi@62 794 return $cache_was_sent;
devi@23 795 }
devi@23 796
devi@25 797 sub save_cache_stat
devi@25 798 {
devi@62 799 open (CACHE, ">$Config{cache_stat}");
devi@62 800 for my $f (keys %Script_Files) {
devi@62 801 print CACHE "$f\t",$Script_Files{$f}->{size},"\t",$Script_Files{$f}->{tell},"\n";
devi@62 802 }
devi@62 803 close(CACHE);
devi@25 804 }
devi@25 805
devi@25 806 sub load_cache_stat
devi@25 807 {
devi@62 808 if (open (CACHE, "$Config{cache_stat}")) {
devi@62 809 while(<CACHE>) {
devi@62 810 chomp;
devi@62 811 my ($f, $size, $tell) = split /\t/;
devi@62 812 $Script_Files{$f}->{size} = $size;
devi@62 813 $Script_Files{$f}->{tell} = $tell;
devi@62 814 }
devi@62 815 close(CACHE);
devi@62 816 };
devi@25 817 }
devi@23 818
devi@23 819
devi@23 820 main();
devi@23 821
devi@25 822 sub process_was_killed
devi@25 823 {
devi@62 824 $Killed = 1;
devi@25 825 }
devi@25 826
devi@98 827 sub reload
devi@98 828 {
devi@98 829 init_config;
devi@98 830 }
devi@98 831
devi@23 832 sub main
devi@23 833 {
devi@23 834
devi@62 835 $| = 1;
devi@23 836
devi@62 837 init_variables();
devi@62 838 init_config();
devi@23 839
devi@27 840
devi@62 841 if ($Config{"mode"} ne "daemon") {
devi@27 842
devi@74 843 # В нормальном режиме работы нужно
devi@74 844 # считать скрипты, обработать их и записать
devi@74 845 # результат выполнения в результирующий файл.
devi@74 846 # После этого завершить работу.
devi@74 847
devi@85 848 # Очистим кэш-файл, если он существовал
devi@85 849 if (open (CACHE, ">", $Config{"cache"})) {
devi@85 850 close(CACHE);
devi@85 851 };
devi@62 852 for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) {
devi@62 853 load_diff_files($lab_log);
devi@62 854 }
devi@62 855 load_command_lines($Config{"input"}, $Config{"input_mask"});
devi@67 856 sort_command_lines;
devi@62 857 #process_command_lines;
devi@62 858 print_command_lines($Config{"cache"});
devi@62 859 }
devi@62 860 else {
devi@62 861 if (open(PIDFILE, $Config{agent_pidfile})) {
devi@62 862 my $pid = <PIDFILE>;
devi@62 863 close(PIDFILE);
devi@62 864 if ($^O eq 'linux' && $pid &&(! -e "/proc/$pid" || !`grep $Config{"l3-agent"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`)) {
devi@62 865 print "Removing stale pidfile\n";
devi@62 866 unlink $Config{agent_pidfile}
devi@62 867 or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!";
devi@62 868 }
devi@62 869 elsif ($^O eq 'freebsd' && $pid && `ps axo uid,pid,command | grep '$<\\s*$pid\\s*$Config{"l3-agent"}' 2> /dev/null`) {
devi@62 870 print "Removing stale pidfile\n";
devi@62 871 unlink $Config{agent_pidfile}
devi@62 872 or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!";
devi@62 873 }
devi@62 874 elsif ($^O eq 'linux' || $^O eq 'freebsd' ) {
devi@62 875 print "l3-agent is already running: pid=$pid; pidfile=$Config{agent_pidfile}\n";
devi@62 876 exit(0);
devi@62 877 }
devi@62 878 else {
devi@62 879 print "Unknown operating system";
devi@62 880 exit(0);
devi@62 881 }
devi@62 882 }
devi@62 883 if ($Config{detach} =~ /^y/i) {
devi@62 884 #$Config{verbose} = "no";
devi@62 885 my $pid = fork;
devi@62 886 exit if $pid;
devi@62 887 die "Couldn't fork: $!" unless defined ($pid);
devi@27 888
devi@62 889 open(PIDFILE, ">", $Config{agent_pidfile})
devi@62 890 or die "Can't open pidfile ". $Config{agent_pidfile}. " for wrting: $!";
devi@62 891 print PIDFILE $$;
devi@62 892 close(PIDFILE);
devi@27 893
devi@62 894 for my $handle (*STDIN, *STDOUT, *STDERR) {
devi@62 895 open ($handle, "+<", "/dev/null")
devi@62 896 or die "can't reopen $handle to /dev/null: $!"
devi@62 897 }
devi@27 898
devi@62 899 POSIX::setsid()
devi@62 900 or die "Can't start a new session: $!";
devi@27 901
devi@62 902 $0 = $Config{"l3-agent"};
devi@62 903
devi@98 904 $SIG{INT} = $SIG{TERM} = \&process_was_killed;
devi@98 905 $SIG{HUP} = \&reload;
devi@98 906
devi@62 907 }
devi@62 908 while (not $Killed) {
devi@62 909 @Command_Lines = ();
devi@62 910 @Command_Lines_Index = ();
devi@62 911 for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) {
devi@62 912 load_diff_files($lab_log);
devi@62 913 }
devi@62 914 load_cache_stat();
devi@62 915 load_command_lines($Config{"input"}, $Config{"input_mask"});
devi@62 916 if (@Command_Lines) {
devi@74 917 sort_command_lines;
devi@65 918 #process_command_lines;
devi@62 919 print_command_lines($Config{"cache"});
devi@62 920 }
devi@62 921 save_cache_stat();
devi@62 922 if (-e $Config{cache} && (stat($Config{cache}))[7]) {
devi@62 923 send_cache() && unlink($Config{cache});
devi@62 924 }
devi@62 925 sleep($Config{"daemon_sleep_interval"} || 1);
devi@62 926 }
devi@62 927
devi@62 928 unlink $Config{agent_pidfile};
devi@62 929 }
devi@23 930
devi@23 931 }
devi@23 932
devi@23 933 sub init_variables
devi@23 934 {
devi@23 935 }