1
0

main.pm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. package Rstat::main;
  2. #
  3. # Copyright (C) Roman Dmitiriev, rnd@rajven.ru
  4. #
  5. use utf8;
  6. use strict;
  7. use English;
  8. no warnings qw( experimental);
  9. use FindBin '$Bin';
  10. use lib "$Bin";
  11. use base 'Exporter';
  12. use vars qw(@EXPORT @ISA);
  13. use Rstat::config;
  14. use Socket;
  15. use IO::Select;
  16. use IO::Handle;
  17. our @ISA = qw(Exporter);
  18. our @EXPORT = qw(
  19. log_file
  20. write_to_file
  21. wrlog
  22. log_session
  23. log_warning
  24. log_info
  25. log_debug
  26. log_error
  27. log_verbose
  28. log_die
  29. timestamp
  30. do_exec
  31. do_exec_ref
  32. do_exit
  33. sendEmail
  34. IsNotRun
  35. IsMyPID
  36. Add_PID
  37. Remove_PID
  38. IsNotLocked
  39. IsMyLock
  40. Add_Lock
  41. Remove_Lock
  42. DefHash
  43. read_file
  44. uniq
  45. strim
  46. trim
  47. is_integer
  48. is_float
  49. run_in_parallel
  50. translit
  51. );
  52. BEGIN
  53. {
  54. #---------------------------------------------------------------------------------------------------------
  55. sub log_file {
  56. return if (!$_[0]);
  57. return if (!$_[1]);
  58. return if (!$_[2]);
  59. open (LG,">>$_[0]") || die("Error open log file $_[0]!!! die...");
  60. my ($sec,$min,$hour,$mday,$mon,$year) = (localtime())[0,1,2,3,4,5];
  61. $mon += 1; $year += 1900;
  62. my @msg = split("\n",$_[2]);
  63. foreach my $row (@msg) {
  64. next if (!$row);
  65. printf LG "%04d%02d%02d-%02d%02d%02d %s [%d] %s\n",$year,$mon,$mday,$hour,$min,$sec,$_[1],$$,$row;
  66. }
  67. close (LG);
  68. if ($< ==0) {
  69. my $uid = getpwnam $log_owner_user;
  70. my $gid = getgrnam $log_owner_user;
  71. if (!$gid) { $gid=getgrnam "root"; }
  72. if (!$uid) { $uid=getpwnam "root"; }
  73. chown $uid, $gid, $_[0];
  74. chmod oct("0660"), $_[0];
  75. }
  76. }
  77. #---------------------------------------------------------------------------------------------------------
  78. sub write_to_file {
  79. return if (!$_[0]);
  80. return if (!$_[1]);
  81. my $f_name = shift;
  82. my $cmd = shift;
  83. my $append = shift;
  84. if ($append) {
  85. open (LG,">>$f_name") || die("Error open file $f_name!!! die...");
  86. } else {
  87. open (LG,">$f_name") || die("Error open file $f_name!!! die...");
  88. }
  89. if (ref($cmd) eq 'ARRAY') {
  90. foreach my $row (@$cmd) {
  91. next if (!$row);
  92. print LG $row."\n";
  93. }
  94. } else {
  95. my @msg = split("\n",$cmd);
  96. foreach my $row (@msg) {
  97. next if (!$row);
  98. print LG $row."\n";
  99. }
  100. }
  101. close (LG);
  102. }
  103. #---------------------------------------------------------------------------------------------------------
  104. sub wrlog {
  105. my $level = shift;
  106. my $string = shift;
  107. my $PRN_LEVEL = 'INFO:';
  108. if ($level == $W_INFO) { log_info($string); }
  109. if ($level == $W_ERROR) { $PRN_LEVEL = 'ERROR:'; log_error($string); }
  110. if ($level == $W_DEBUG) { $PRN_LEVEL = 'DEBUG'; log_debug($string); }
  111. my @msg = split("\n",$string);
  112. foreach my $row (@msg) {
  113. next if (!$row);
  114. print $PRN_LEVEL.' '.$row."\n";
  115. }
  116. }
  117. #---------------------------------------------------------------------------------------------------------
  118. sub log_session { log_file($LOG_COMMON,"SESSION:",$_[0]) if ($log_enable); }
  119. #---------------------------------------------------------------------------------------------------------
  120. sub log_info { log_file($LOG_COMMON,"INFO:",$_[0]) if ($log_enable); }
  121. #---------------------------------------------------------------------------------------------------------
  122. sub log_verbose { log_file($LOG_COMMON,"VERBOSE:",$_[0]) if ($log_enable); }
  123. #---------------------------------------------------------------------------------------------------------
  124. sub log_warning { log_file($LOG_COMMON,"WARN:",$_[0]) if ($log_enable); }
  125. #---------------------------------------------------------------------------------------------------------
  126. sub log_debug { log_file($LOG_DEBUG,"DEBUG:",$_[0]) if $debug; }
  127. #---------------------------------------------------------------------------------------------------------
  128. sub log_error { log_file($LOG_ERR,"ERROR:",$_[0]) if ($log_enable); }
  129. #---------------------------------------------------------------------------------------------------------
  130. sub log_die {
  131. wrlog($W_ERROR,$_[0]);
  132. my $worktime = time()-$BASETIME;
  133. log_info("Script work $worktime sec.");
  134. sendEmail("$HOSTNAME - $MY_NAME die! ","Process: $MY_NAME aborted with error:\n$_[0]");
  135. die ($_[0]);
  136. }
  137. #---------------------------------------------------------------------------------------------------------
  138. sub timestamp {
  139. my $worktime = time()-$BASETIME;
  140. log_info("TimeStamp: $worktime sec.");
  141. }
  142. #---------------------------------------------------------------------------------------------------------.
  143. sub do_exec_ref {
  144. my $ret = `$_[0]`;
  145. my $res = $?;
  146. my %result;
  147. chomp($ret);
  148. $result{output}=$ret;
  149. $result{status}=$res;
  150. log_debug("Run: $_[0] Output:\n$ret\nResult code: $res");
  151. if ($res eq "0") { log_info("Run: $_[0] - $ret"); } else { log_error("Run: $_[0] - $ret"); }
  152. return %result;
  153. }
  154. #---------------------------------------------------------------------------------------------------------
  155. sub do_exec {
  156. my $ret = `$_[0]`;
  157. my $res = $?;
  158. log_debug("Run: $_[0] Output:\n$ret\nResult code: $res");
  159. if ($res eq "0") {
  160. log_info("Run: $_[0] - $ret");
  161. } else {
  162. $ret = "Error";
  163. log_error("Run: $_[0] - $ret");
  164. }
  165. return $ret;
  166. }
  167. #---------------------------------------------------------------------------------------------------------
  168. sub do_exit {
  169. my $worktime = time()-$BASETIME;
  170. my $code;
  171. if ($_[0]) { $code = $_[0]; } else { $code = 0; }
  172. log_info("Script work $worktime sec. Exit code: $code");
  173. exit $code;
  174. }
  175. #---------------------------------------------------------------------------------------------------------
  176. sub sendEmail {
  177. my ($subject, $message, $crf) = @_;
  178. return if (!$send_email);
  179. my $sendmail = '/sbin/sendmail';
  180. open(MAIL, "|$sendmail -oi -t");
  181. print MAIL "From: $sender_email\n";
  182. print MAIL "To: $admin_email\n";
  183. print MAIL "Subject: $subject\nMIME-Version: 1.0\nContent-Language: ru\nContent-Type: text/html; charset=utf-8\nContent-Transfer-Encoding: 8bit\n\n";
  184. print MAIL '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'."\n";
  185. print MAIL '<html xmlns="http://www.w3.org/1999/xhtml">'."\n";
  186. print MAIL "<head><title>$subject </title></head><body>\n";
  187. my @msg = split("\n",$message);
  188. foreach my $row (@msg) {
  189. if ($crf) { print MAIL "$row<br>"; } else { print MAIL "$row\n"; };
  190. }
  191. print MAIL "</body></html>\n";
  192. close(MAIL);
  193. log_info("Send email from $sender_email to $admin_email with subject: $subject");
  194. log_debug("Body:\n$message");
  195. }
  196. #---------------------------------------------------------------------------------------------------------
  197. ### Check few run script
  198. sub IsNotRun {
  199. my $pname = shift;
  200. my $lockfile = $pname.".pid";
  201. # if pid file not exists - OK
  202. log_debug("Check what pid file $lockfile exists.");
  203. if (! -e $lockfile) { log_debug("pid file not found. Continue."); return 1; }
  204. open (FF,"<$lockfile") or log_die("can't open file $lockfile: $!");
  205. my $lockid = <FF>;
  206. close(FF);
  207. chomp($lockid);
  208. # If the process ID belongs to the current program - OK
  209. if ($lockid eq $$) { log_debug("pid file found, but owner is this process. Continue. "); return 1; }
  210. # if owner of this process ID not exists - OK
  211. my $process_count = `ps -p $lockid | grep \'$lockid\' | wc -l`;
  212. chomp($process_count);
  213. log_debug("Process count with id $lockid is $process_count");
  214. if ($process_count==0) { log_debug("pid file found, but owner process not found. Remove lock file and continue. "); unlink $lockfile; return 1; }
  215. log_debug("Another proceess with name $MY_NAME pid: $lockid already worked. ");
  216. return 0;
  217. }
  218. #---------------------------------------------------------------------------------------------------------
  219. sub IsMyPID {
  220. my $pname = shift;
  221. my $lockfile = $pname.".pid";
  222. log_debug("Check what pid file $lockfile exists.");
  223. if (! -e $lockfile) { log_debug("pid file not found. Continue."); return 1; }
  224. open (FF,"<$lockfile") or log_die "can't open file $lockfile: $!";
  225. my $lockid = <FF>;
  226. close(FF);
  227. chomp($lockid);
  228. if ($lockid eq $$) { log_debug("pid file is my. continue."); return 1; }
  229. log_debug("Another proceess with name $MY_NAME pid: $lockid already worked. ");
  230. return 0;
  231. }
  232. #---------------------------------------------------------------------------------------------------------
  233. sub Add_PID {
  234. my $pname = shift;
  235. my $lockfile = $pname.".pid";
  236. log_debug("Try create lock file $lockfile");
  237. open (FF,">$lockfile") or log_die "can't open file $lockfile: $!";
  238. flock(FF,2) or log_die "can't flock $lockfile: $!";
  239. print FF $$;
  240. close(FF);
  241. log_debug("Ok.");
  242. return 1;
  243. }
  244. #---------------------------------------------------------------------------------------------------------
  245. sub Remove_PID {
  246. my $pname = shift;
  247. my $lockfile = $pname.".pid";
  248. log_debug("Check what pid file $lockfile exists.");
  249. if (! -e $lockfile) { log_debug("pid file not exists. Continue."); return 1; }
  250. unlink $lockfile or return 0;
  251. log_debug("pid file $lockfile removed.");
  252. return 1;
  253. }
  254. #---------------------------------------------------------------------------------------------------------
  255. sub IsNotLocked {
  256. my $lockfile = $_[0] . ".lock";
  257. log_debug("Check what lock file $lockfile exists.");
  258. if (! -e $lockfile) { log_debug("lock file not found. Continue."); return 1; }
  259. open (FF,"<$lockfile") or log_die "can't open file $lockfile: $!";
  260. my $lockid = <FF>;
  261. close(FF);
  262. chomp($lockid);
  263. if ($lockid eq $$) { log_debug("lock file found, but it is owner is this process. Continue. "); return 1; }
  264. my $process_count = `ps -p $lockid | grep \'$lockid\' | wc -l`;
  265. if ($process_count lt 1) { log_debug("lock file found, but owner process not found. Remove lock file and continue. "); unlink $lockfile; return 1; }
  266. log_debug("Another proceess with pid: $lockid already use $_[0]");
  267. return 0;
  268. }
  269. #---------------------------------------------------------------------------------------------------------
  270. sub IsMyLock {
  271. my $lockfile = $_[0] . ".lock";
  272. log_debug("Check what lock file $lockfile exists.");
  273. if (! -e $lockfile) { log_debug("lock file not found. Continue."); return 0; }
  274. open (FF,"<$lockfile") or log_die "can't open file $lockfile: $!";
  275. my $lockid = <FF>;
  276. close(FF);
  277. chomp($lockid);
  278. if ($lockid eq $$) { log_debug("lock file found, but it is owner is this process. Continue. "); return 1; }
  279. log_debug("file $_[0] used by process with pid: $lockid");
  280. return 0;
  281. }
  282. #---------------------------------------------------------------------------------------------------------
  283. sub Add_Lock {
  284. if (!IsNotLocked($_[0])) { return 0; }
  285. my $lockfile = $_[0] . ".lock";
  286. open (FF,">$lockfile") or log_die "can't open file $lockfile: $!";
  287. flock(FF,2) or log_die "can't flock $lockfile: $!";
  288. print FF $$;
  289. close(FF);
  290. log_debug("Create lock file for $_[0]");
  291. return 1;
  292. }
  293. #---------------------------------------------------------------------------------------------------------
  294. sub Remove_Lock {
  295. if (!IsNotLocked($_[0])) { return 0; }
  296. my $lockfile = $_[0] . ".lock";
  297. if (! -e $lockfile) { return 1; }
  298. unlink $lockfile or return 0;
  299. log_debug("Lock file for $_[0] removed");
  300. return 1;
  301. }
  302. #---------------------------------------------------------------------------------------------------------
  303. sub DefHash {
  304. my $hash=$_[0];
  305. my $num_list = $_[1];
  306. my %num_keys;
  307. if ($num_list) {
  308. my @ret_num = split(' ',$num_list);
  309. %num_keys = map { $_, 1 } @ret_num;
  310. }
  311. foreach my $key (keys %$hash) {
  312. my $null_value = "";
  313. $null_value = 0 if (defined $num_keys{$key});
  314. $hash->{$key}=$null_value if (!defined($hash->{$key}));
  315. }
  316. return $hash;
  317. }
  318. #---------------------------------------------------------------------------------------------------------
  319. sub read_file {
  320. my $filename = shift;
  321. return if (!$filename);
  322. return if (!-e $filename);
  323. open (FF,"<$filename") or die "unable to open file $filename!" ;
  324. my @tmp=<FF>;
  325. close(FF);
  326. chomp(@tmp);
  327. return @tmp;
  328. }
  329. #---------------------------------------------------------------------------------------------------------
  330. sub uniq (\@) {
  331. my @tmp = @{(shift)};
  332. if (scalar(@tmp) eq 0) { return @tmp; }
  333. chomp(@tmp);
  334. my %newlist = map { $_, 1 } @tmp;
  335. return keys %newlist;
  336. }
  337. #---------------------------------------------------------------------------------------------------------
  338. sub strim {
  339. my $str=shift;
  340. return if (!$str);
  341. #$str =~ s/.*[^[:print:]]+//g;
  342. #$str =~ s/[^[:print:]]+//g;
  343. #$str =~ s/[^(a-z|A-Z|0-9|\:|\-|\s|\.)]//g;
  344. #$str =~ s/[:^print:]//g;
  345. $str =~ s/[^[:ascii:]]//g;
  346. $str =~ s/^\s+//g;
  347. $str =~ s/\s+$//g;
  348. return $str;
  349. }
  350. #---------------------------------------------------------------------------------------------------------
  351. sub trim {
  352. my $str=shift;
  353. return if (!$str);
  354. $str =~ s/\n/ /g;
  355. $str =~ s/^\s+//g;
  356. $str =~ s/\s+$//g;
  357. return $str;
  358. }
  359. #---------------------------------------------------------------------------------------------------------
  360. sub is_integer {
  361. defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
  362. }
  363. #---------------------------------------------------------------------------------------------------------
  364. sub is_float {
  365. defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/;
  366. }
  367. #---------------------------------------------------------------------------------------------------------
  368. sub run_in_parallel(\@) {
  369. my @commands = @{(shift)};
  370. my @result = ();
  371. return @result if (!@commands or !scalar(@commands));
  372. my $count = scalar(@commands);
  373. my $start = 0;
  374. while ($start<=$count-1) {
  375. my @run_list=();
  376. my $select = IO::Select->new();
  377. my $stop = $start + $parallel_process_count;
  378. $stop=$count-1 if ($stop >=$count);
  379. for (my $index = $start; $index <=$stop; $index++) {
  380. next if (!$commands[$index]);
  381. my $cmd=$commands[$index];
  382. log_info("Starting ".$cmd);
  383. my ($hchild, $hparent, $childid);
  384. socketpair($hchild, $hparent, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!";
  385. $childid = fork;
  386. die "cannot fork" if($childid == -1);
  387. # redirect child Input|Output
  388. unless($childid) {
  389. open STDIN, "<&", $hparent;
  390. open STDOUT, ">&", $hparent;
  391. open STDERR, ">&", $hparent;
  392. close $hparent;
  393. close $hchild;
  394. $select->remove($_) and close $_ for($select->handles);
  395. exec "/bin/nice -n 15 ".$cmd;
  396. }
  397. close $hparent;
  398. $select->add($hchild);
  399. }
  400. while (my @ready = $select->can_read) {
  401. next if (!@ready or !scalar(@ready));
  402. for my $read(@ready) {
  403. if($read->eof || $read->error) {
  404. # child exit
  405. $select->remove($read);
  406. close $read;
  407. next;
  408. }
  409. if(defined(my $str = <$read>)) {
  410. log_info("Read:".$str);
  411. push(@result,$str);
  412. }
  413. }
  414. }
  415. $start = $stop+1;
  416. }
  417. return (@result);
  418. }
  419. sub translit {
  420. my $textline=shift;
  421. return if (!$textline);
  422. $textline =~ s/А/A/g; $textline =~ s/а/a/g;
  423. $textline =~ s/Б/B/g; $textline =~ s/б/b/g;
  424. $textline =~ s/В/V/g; $textline =~ s/в/v/g;
  425. $textline =~ s/Г/G/g; $textline =~ s/г/g/g;
  426. $textline =~ s/Д/D/g; $textline =~ s/д/d/g;
  427. $textline =~ s/Е/E/g; $textline =~ s/е/e/g;
  428. $textline =~ s/Ё/E/g; $textline =~ s/ё/e/g;
  429. $textline =~ s/Ж/Zh/g; $textline =~ s/ж/zh/g;
  430. $textline =~ s/З/Z/g; $textline =~ s/з/z/g;
  431. $textline =~ s/И/I/g; $textline =~ s/и/i/g;
  432. $textline =~ s/Й/I/g; $textline =~ s/й/i/g;
  433. $textline =~ s/К/K/g; $textline =~ s/к/k/g;
  434. $textline =~ s/Л/L/g; $textline =~ s/л/l/g;
  435. $textline =~ s/М/M/g; $textline =~ s/м/m/g;
  436. $textline =~ s/Н/N/g; $textline =~ s/н/n/g;
  437. $textline =~ s/О/O/g; $textline =~ s/о/o/g;
  438. $textline =~ s/П/P/g; $textline =~ s/п/p/g;
  439. $textline =~ s/Р/R/g; $textline =~ s/р/r/g;
  440. $textline =~ s/ТС/T-S/g; $textline =~ s/Тс/T-s/g; $textline =~ s/тс/t-s/g;
  441. $textline =~ s/С/S/g; $textline =~ s/с/s/g;
  442. $textline =~ s/Т/T/g; $textline =~ s/т/t/g;
  443. $textline =~ s/У/U/g; $textline =~ s/у/u/g;
  444. $textline =~ s/Ф/F/g; $textline =~ s/ф/f/g;
  445. $textline =~ s/Х/Kh/g; $textline =~ s/х/kh/g;
  446. $textline =~ s/Ц/Ts/g; $textline =~ s/ц/ts/g;
  447. $textline =~ s/Ч/Ch/g; $textline =~ s/ч/ch/g;
  448. $textline =~ s/Ш/Sh/g; $textline =~ s/ш/sh/g;
  449. $textline =~ s/Щ/Shch/g; $textline =~ s/щ/shch/g;
  450. $textline =~ s/Ь/'/g; $textline =~ s/ь/'/g;
  451. $textline =~ s/Ы/Y/g; $textline =~ s/ы/y/g;
  452. $textline =~ s/Ъ/''/g; $textline =~ s/ъ/''/g;
  453. $textline =~ s/Э/E/g; $textline =~ s/э/e/g;
  454. $textline =~ s/Ю/Yu/g; $textline =~ s/ю/yu/g;
  455. $textline =~ s/Я/Ya/g; $textline =~ s/я/ya/g;
  456. return $textline;
  457. }
  458. #log_file($LOG_COMMON,"INFO:","----------------------------------------------------------------------------------------");
  459. #log_file($LOG_COMMON,"INFO:","Run script $0. Pid: $$ Pid file: $SPID.pid");
  460. #log_file($LOG_COMMON,"INFO:","User uid: $< Effective uid: $>");
  461. #log_file($LOG_COMMON,"INFO:","Status:");
  462. #log_file($LOG_COMMON,"INFO:","Logging enabled: $log_enable");
  463. #log_file($LOG_COMMON,"INFO:","Logging debug: $debug");
  464. 1;
  465. }