main.pm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. package eyelib::main;
  2. #
  3. # Copyright (C) Roman Dmitriev, rnd@rajven.ru
  4. #
  5. use utf8;
  6. use open ":encoding(utf8)";
  7. use Encode;
  8. use strict;
  9. use English;
  10. use FindBin '$Bin';
  11. use lib "/opt/Eye/scripts";
  12. use base 'Exporter';
  13. use vars qw(@EXPORT @ISA);
  14. use eyelib::config;
  15. use Socket;
  16. use POSIX;
  17. use IO::Select;
  18. use IO::Handle;
  19. use Crypt::CBC;
  20. use MIME::Base64;
  21. our @ISA = qw(Exporter);
  22. our @EXPORT = qw(
  23. get_first_line
  24. isNotifyCreate
  25. isNotifyUpdate
  26. isNotifyDelete
  27. isNotifyNone
  28. hasNotifyFlag
  29. log_file
  30. write_to_file
  31. wrlog
  32. log_session
  33. log_warning
  34. log_info
  35. log_debug
  36. log_error
  37. log_verbose
  38. log_die
  39. in_array
  40. timestamp
  41. do_exec
  42. do_exec_ref
  43. do_exit
  44. hash_to_kv_csv
  45. sendEmail
  46. IsNotRun
  47. IsMyPID
  48. Add_PID
  49. Remove_PID
  50. IsNotLocked
  51. IsMyLock
  52. Add_Lock
  53. Remove_Lock
  54. DefHash
  55. read_file
  56. uniq
  57. strim
  58. trim
  59. hash_to_text
  60. is_integer
  61. is_float
  62. run_in_parallel
  63. translit
  64. crypt_string
  65. decrypt_string
  66. netdev_set_auth
  67. GetNowTime
  68. GetUnixTimeByStr
  69. GetTimeStrByUnixTime
  70. );
  71. BEGIN
  72. {
  73. #---------------------------------------------------------------------------------------------------------------
  74. sub get_first_line {
  75. my $msg = shift;
  76. if (!$msg) { return; }
  77. if ($msg=~ /(.*)(\n|\<br\>)/) {
  78. $msg = $1 if ($1);
  79. chomp($msg);
  80. }
  81. return $msg;
  82. }
  83. #---------------------------------------------------------------------------------------------------------
  84. # Проверяет, установлен ли флаг создания
  85. sub isNotifyCreate {
  86. my ($flags) = @_;
  87. return ($flags & NOTIFY_CREATE) == NOTIFY_CREATE;
  88. }
  89. #---------------------------------------------------------------------------------------------------------
  90. # Проверяет, установлен ли флаг изменения
  91. sub isNotifyUpdate {
  92. my ($flags) = @_;
  93. return ($flags & NOTIFY_UPDATE) == NOTIFY_UPDATE;
  94. }
  95. #---------------------------------------------------------------------------------------------------------
  96. # Проверяет, установлен ли флаг удаления
  97. sub isNotifyDelete {
  98. my ($flags) = @_;
  99. return ($flags & NOTIFY_DELETE) == NOTIFY_DELETE;
  100. }
  101. #---------------------------------------------------------------------------------------------------------
  102. # Проверяет, отключены ли все уведомления
  103. sub isNotifyNone {
  104. my ($flags) = @_;
  105. return $flags == NOTIFY_NONE;
  106. }
  107. #---------------------------------------------------------------------------------------------------------
  108. # Проверяет, установлен ли конкретный флаг
  109. sub hasNotifyFlag {
  110. my ($flags, $flagToCheck) = @_;
  111. return ($flags & $flagToCheck) == $flagToCheck;
  112. }
  113. #---------------------------------------------------------------------------------------------------------
  114. sub log_file {
  115. return if (!$_[0]);
  116. return if (!$_[1]);
  117. return if (!$_[2]);
  118. # Вместо die - предупреждение и возврат
  119. unless (open (LG,">>$_[0]")) {
  120. # Пишем в stderr как последнее средство
  121. print STDERR "WARNING: Cannot open log file $_[0]: $!\n";
  122. return;
  123. }
  124. my ($sec,$min,$hour,$mday,$mon,$year) = (localtime())[0,1,2,3,4,5];
  125. $mon += 1; $year += 1900;
  126. my @msg = split("\n",$_[2]);
  127. foreach my $row (@msg) {
  128. next if (!$row);
  129. printf LG "%04d%02d%02d-%02d%02d%02d %s [%d] %s\n",$year,$mon,$mday,$hour,$min,$sec,$_[1],$$,$row;
  130. }
  131. close (LG);
  132. if ($< ==0) {
  133. my $uid = getpwnam $log_owner_user;
  134. my $gid = getgrnam $log_owner_user;
  135. if (!$gid) { $gid=getgrnam "root"; }
  136. if (!$uid) { $uid=getpwnam "root"; }
  137. chown $uid, $gid, $_[0];
  138. chmod oct("0660"), $_[0];
  139. }
  140. }
  141. #---------------------------------------------------------------------------------------------------------
  142. sub write_to_file {
  143. return if (!$_[0]);
  144. return if (!$_[1]);
  145. my $f_name = shift;
  146. my $cmd = shift;
  147. my $append = shift;
  148. if ($append) {
  149. open (LG,">>$f_name") || die("Error open file $f_name!!! die...");
  150. } else {
  151. open (LG,">$f_name") || die("Error open file $f_name!!! die...");
  152. }
  153. binmode(LG,':utf8');
  154. if (ref($cmd) eq 'ARRAY') {
  155. foreach my $row (@$cmd) {
  156. next if (!$row);
  157. print LG $row."\n";
  158. }
  159. } else {
  160. my @msg = split("\n",$cmd);
  161. foreach my $row (@msg) {
  162. next if (!$row);
  163. print LG $row."\n";
  164. }
  165. }
  166. close (LG);
  167. }
  168. #---------------------------------------------------------------------------------------------------------
  169. sub wrlog {
  170. my $level = shift;
  171. my $string = shift;
  172. my $PRN_LEVEL = 'INFO:';
  173. if ($level == $W_INFO) { log_info($string); }
  174. if ($level == $W_ERROR) { $PRN_LEVEL = 'ERROR:'; log_error($string); }
  175. if ($level == $W_DEBUG) { $PRN_LEVEL = 'DEBUG'; log_debug($string); }
  176. my @msg = split("\n",$string);
  177. foreach my $row (@msg) {
  178. next if (!$row);
  179. print $PRN_LEVEL.' '.$row."\n";
  180. }
  181. }
  182. #---------------------------------------------------------------------------------------------------------
  183. sub log_session { log_file($LOG_COMMON,"SESSION:",$_[0]) if ($log_enable); }
  184. #---------------------------------------------------------------------------------------------------------
  185. sub log_info { log_file($LOG_COMMON,"INFO:",$_[0]) if ($log_enable); }
  186. #---------------------------------------------------------------------------------------------------------
  187. sub log_verbose { log_file($LOG_COMMON,"VERBOSE:",$_[0]) if ($log_enable); }
  188. #---------------------------------------------------------------------------------------------------------
  189. sub log_warning { log_file($LOG_COMMON,"WARN:",$_[0]) if ($log_enable); }
  190. #---------------------------------------------------------------------------------------------------------
  191. sub log_debug { log_file($LOG_DEBUG,"DEBUG:",$_[0]) if $debug; }
  192. #---------------------------------------------------------------------------------------------------------
  193. sub log_error { log_file($LOG_ERR,"ERROR:",$_[0]) if ($log_enable); }
  194. #---------------------------------------------------------------------------------------------------------
  195. sub log_die {
  196. wrlog($W_ERROR,$_[0]);
  197. my $worktime = time()-$BASETIME;
  198. log_info("Script work $worktime sec.");
  199. #sendEmail("$HOSTNAME - $MY_NAME die! ","Process: $MY_NAME aborted with error:\n$_[0]");
  200. die ($_[0]);
  201. }
  202. #---------------------------------------------------------------------------------------------------------
  203. sub timestamp {
  204. my $worktime = time()-$BASETIME;
  205. #print "TimeStamp: $worktime sec.\n";
  206. log_info("TimeStamp: $worktime sec.");
  207. }
  208. #---------------------------------------------------------------------------------------------------------
  209. sub in_array {
  210. my $arr = shift;
  211. my @tmp = ();
  212. if (ref($arr)=~'ARRAY') { @tmp = @{$arr}; } else { push(@tmp,$arr); }
  213. my $value = shift;
  214. my %num = map { $_, 1 } @tmp;
  215. return $num{$value} || 0;
  216. }
  217. #---------------------------------------------------------------------------------------------------------.
  218. sub hash_to_kv_csv {
  219. my ($hash_ref, $delimiter) = @_;
  220. $delimiter ||= ',';
  221. return '' unless $hash_ref && %$hash_ref;
  222. # Экранируем специальные символы
  223. my $escape = sub {
  224. my $value = shift;
  225. return '' unless defined $value;
  226. # Если значение содержит кавычки или запятые - заключаем в кавычки
  227. if ($value =~ /["$delimiter]/) {
  228. $value =~ s/"/""/g;
  229. return '"' . $value . '"';
  230. }
  231. return $value;
  232. };
  233. # Формируем пары ключ=>значение
  234. my @pairs;
  235. while (my ($key, $value) = each %$hash_ref) {
  236. push @pairs, $escape->($key) . '=>' . $escape->($value);
  237. }
  238. return join($delimiter, sort @pairs);
  239. }
  240. #---------------------------------------------------------------------------------------------------------.
  241. sub do_exec_ref {
  242. my $ret = `$_[0] 2>&1`;
  243. my $res = $?;
  244. my %result;
  245. chomp($ret);
  246. $result{output}=$ret;
  247. $result{status}=$res;
  248. log_debug("Run: $_[0] Output:\n$ret\nResult code: $res");
  249. if ($res eq "0") { log_info("Run: $_[0] - $ret"); } else { log_error("Run: $_[0] - $ret"); }
  250. return %result;
  251. }
  252. #---------------------------------------------------------------------------------------------------------
  253. sub do_exec {
  254. my $ret = `$_[0]`;
  255. my $res = $?;
  256. log_debug("Run: $_[0] Output:\n$ret\nResult code: $res");
  257. if ($res eq "0") {
  258. log_info("Run: $_[0] - $ret");
  259. } else {
  260. $ret = "Error";
  261. log_error("Run: $_[0] - $ret");
  262. }
  263. return $ret;
  264. }
  265. #---------------------------------------------------------------------------------------------------------
  266. sub do_exit {
  267. my $worktime = time()-$BASETIME;
  268. my $code;
  269. if ($_[0]) { $code = $_[0]; } else { $code = 0; }
  270. log_info("Script work $worktime sec. Exit code: $code");
  271. exit $code;
  272. }
  273. #---------------------------------------------------------------------------------------------------------
  274. sub encode_mime_header {
  275. my ($str) = @_;
  276. return $str if $str =~ /^[[:ascii:]]*$/;
  277. my $b64 = encode_base64($str, '');
  278. $b64 =~ s/\s+$//;
  279. return "=?UTF-8?B?$b64?=";
  280. }
  281. #---------------------------------------------------------------------------------------------------------
  282. sub sendEmail {
  283. my ($subject, $msg, $use_br) = @_;
  284. return unless defined $msg && length $msg;
  285. return unless $send_email;
  286. unless (defined $sender_email && defined $admin_email) {
  287. log_error("Email addresses not defined");
  288. return;
  289. }
  290. # Санитизация (оставляет Unicode буквы/цифры)
  291. $subject =~ s/[^\p{L}\p{N}\s\-\.\,\!\?]//g;
  292. $msg =~ s/\r//g;
  293. my $html_message = <<"END_HTML";
  294. <!DOCTYPE html>
  295. <html xmlns="http://www.w3.org/1999/xhtml">
  296. <head>
  297. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  298. <title>$subject</title>
  299. </head>
  300. <body>
  301. <div>
  302. END_HTML
  303. my @lines = split(/\n/, $msg);
  304. foreach my $line (@lines) {
  305. $line = htmlspecialchars($line);
  306. $html_message .= $use_br ? "$line<br>\n" : "$line\n";
  307. }
  308. $html_message .= "</div>\n</body>\n</html>\n";
  309. # Кодируем Unicode-строку в байты UTF-8, затем в base64
  310. my $html_utf8_bytes = encode('UTF-8', $html_message);
  311. my $encoded_html = encode_base64($html_utf8_bytes);
  312. my $boundary = '----=' . time() . int(rand(1000));
  313. my $encoded_subject = encode_mime_header($subject);
  314. my $headers = <<"END_HEADERS";
  315. From: $sender_email
  316. To: $admin_email
  317. Subject: $encoded_subject
  318. MIME-Version: 1.0
  319. Content-Type: multipart/mixed; boundary="$boundary"
  320. END_HEADERS
  321. my $mime_message = <<"END_MIME";
  322. --$boundary
  323. Content-Type: text/html; charset=utf-8
  324. Content-Transfer-Encoding: base64
  325. $encoded_html
  326. --$boundary--
  327. END_MIME
  328. my $sendmail = '/usr/sbin/sendmail';
  329. unless (-x $sendmail) {
  330. log_error("Sendmail not found or not executable at $sendmail");
  331. return;
  332. }
  333. unless (open(MAIL, "|$sendmail -oi -t")) {
  334. log_error("Failed to open sendmail: $!");
  335. return;
  336. }
  337. print MAIL $headers;
  338. print MAIL $mime_message;
  339. close(MAIL) or log_error("Failed to send email: $!");
  340. log_info("Sent email from $sender_email to $admin_email with subject: $subject");
  341. log_debug("Email body:\n$msg");
  342. }
  343. #---------------------------------------------------------------------------------------------------------
  344. sub hash_to_text {
  345. my ($hash_ref, $indent, $seen) = @_;
  346. $indent ||= 0;
  347. $seen ||= {};
  348. return 'undef' unless defined $hash_ref;
  349. if (ref $hash_ref eq 'HASH') {
  350. # Защита от циклических ссылок
  351. my $addr = refaddr($hash_ref);
  352. if ($seen->{$addr}) {
  353. return '';
  354. }
  355. $seen->{$addr} = 1;
  356. my $spaces = ' ' x $indent;
  357. my @lines;
  358. for my $key (sort keys %$hash_ref) {
  359. my $value = $hash_ref->{$key};
  360. my $formatted_key = $key =~ /^[a-zA-Z_]\w*$/ ? $key : "'$key'";
  361. my $formatted_value;
  362. if (ref $value eq 'HASH') {
  363. $formatted_value = ":\n" . hash_to_text($value, $indent + 1, $seen) . "\n$spaces";
  364. }
  365. elsif (ref $value eq 'ARRAY') {
  366. $formatted_value = array_to_text($value, $indent + 1, $seen);
  367. }
  368. elsif (ref $value) {
  369. $formatted_value = '[' . ref($value) . ']';
  370. }
  371. elsif (!defined $value) {
  372. $formatted_value = '';
  373. }
  374. else {
  375. $formatted_value = "'$value'";
  376. }
  377. push @lines, "$spaces $formatted_key => $formatted_value" if ($formatted_value);
  378. }
  379. return join(",\n", @lines) || "$spaces # empty";
  380. }
  381. else {
  382. return "'$hash_ref'";
  383. }
  384. }
  385. #---------------------------------------------------------------------------------------------------------
  386. sub array_to_text {
  387. my ($array_ref, $indent, $seen) = @_;
  388. $indent ||= 0;
  389. $seen ||= {};
  390. return '[]' unless @$array_ref;
  391. my $spaces = ' ' x $indent;
  392. my @lines;
  393. foreach my $item (@$array_ref) {
  394. my $formatted_item;
  395. if (ref $item eq 'HASH') {
  396. $formatted_item = ":\n" . hash_to_text($item, $indent + 1, $seen) . "\n$spaces";
  397. }
  398. elsif (ref $item eq 'ARRAY') {
  399. $formatted_item = array_to_text($item, $indent + 1, $seen);
  400. }
  401. elsif (ref $item) {
  402. $formatted_item = '[' . ref($item) . ']';
  403. }
  404. elsif (!defined $item) {
  405. $formatted_item = '';
  406. }
  407. else {
  408. $formatted_item = "'$item'";
  409. }
  410. push @lines, "$spaces $formatted_item" if ($formatted_item);
  411. }
  412. return "[\n" . join(",\n", @lines) . "\n$spaces]";
  413. }
  414. #---------------------------------------------------------------------------------------------------------
  415. # Вспомогательная функция для получения адреса ссылки
  416. sub refaddr {
  417. my $ref = shift;
  418. return "$ref" =~ /\(0x([0-9a-f]+)\)$/ ? "0x$1" : "$ref";
  419. }
  420. #---------------------------------------------------------------------------------------------------------
  421. ### Check few run script
  422. sub IsNotRun {
  423. my $pname = shift;
  424. my $lockfile = $pname.".pid";
  425. # if pid file not exists - OK
  426. log_debug("Check what pid file $lockfile exists.");
  427. if (! -e $lockfile) { log_debug("pid file not found. Continue."); return 1; }
  428. open (FF,"<$lockfile") or log_die("can't open file $lockfile: $!");
  429. my $lockid = <FF>;
  430. close(FF);
  431. chomp($lockid);
  432. # If the process ID belongs to the current program - OK
  433. if ($lockid eq $$) { log_debug("pid file found, but owner is this process. Continue. "); return 1; }
  434. # if owner of this process ID not exists - OK
  435. my $process_count = `ps -p $lockid | grep \'$lockid\' | wc -l`;
  436. chomp($process_count);
  437. log_debug("Process count with id $lockid is $process_count");
  438. if ($process_count==0) { log_debug("pid file found, but owner process not found. Remove lock file and continue. "); unlink $lockfile; return 1; }
  439. log_debug("Another proceess with name $MY_NAME pid: $lockid already worked. ");
  440. return 0;
  441. }
  442. #---------------------------------------------------------------------------------------------------------
  443. sub IsMyPID {
  444. my $pname = shift;
  445. my $lockfile = $pname.".pid";
  446. log_debug("Check what pid file $lockfile exists.");
  447. if (! -e $lockfile) { log_debug("pid file not found. Continue."); return 1; }
  448. open (FF,"<$lockfile") or log_die "can't open file $lockfile: $!";
  449. my $lockid = <FF>;
  450. close(FF);
  451. chomp($lockid);
  452. if ($lockid eq $$) { log_debug("pid file is my. continue."); return 1; }
  453. log_debug("Another proceess with name $MY_NAME pid: $lockid already worked. ");
  454. return 0;
  455. }
  456. #---------------------------------------------------------------------------------------------------------
  457. sub Add_PID {
  458. my $pname = shift;
  459. my $lockfile = $pname.".pid";
  460. log_debug("Try create lock file $lockfile");
  461. open (FF,">$lockfile") or log_die "can't open file $lockfile: $!";
  462. flock(FF,2) or log_die "can't flock $lockfile: $!";
  463. print FF $$;
  464. close(FF);
  465. log_debug("Ok.");
  466. return 1;
  467. }
  468. #---------------------------------------------------------------------------------------------------------
  469. sub Remove_PID {
  470. my $pname = shift;
  471. my $lockfile = $pname.".pid";
  472. log_debug("Check what pid file $lockfile exists.");
  473. if (! -e $lockfile) { log_debug("pid file not exists. Continue."); return 1; }
  474. unlink $lockfile or return 0;
  475. log_debug("pid file $lockfile removed.");
  476. return 1;
  477. }
  478. #---------------------------------------------------------------------------------------------------------
  479. sub IsNotLocked {
  480. my $lockfile = $_[0] . ".lock";
  481. log_debug("Check what lock file $lockfile exists.");
  482. if (! -e $lockfile) { log_debug("lock file not found. Continue."); return 1; }
  483. open (FF,"<$lockfile") or log_die "can't open file $lockfile: $!";
  484. my $lockid = <FF>;
  485. close(FF);
  486. chomp($lockid);
  487. if ($lockid eq $$) { log_debug("lock file found, but it is owner is this process. Continue. "); return 1; }
  488. my $process_count = `ps -p $lockid | grep \'$lockid\' | wc -l`;
  489. if ($process_count lt 1) { log_debug("lock file found, but owner process not found. Remove lock file and continue. "); unlink $lockfile; return 1; }
  490. log_debug("Another proceess with pid: $lockid already use $_[0]");
  491. return 0;
  492. }
  493. #---------------------------------------------------------------------------------------------------------
  494. sub IsMyLock {
  495. my $lockfile = $_[0] . ".lock";
  496. log_debug("Check what lock file $lockfile exists.");
  497. if (! -e $lockfile) { log_debug("lock file not found. Continue."); return 0; }
  498. open (FF,"<$lockfile") or log_die "can't open file $lockfile: $!";
  499. my $lockid = <FF>;
  500. close(FF);
  501. chomp($lockid);
  502. if ($lockid eq $$) { log_debug("lock file found, but it is owner is this process. Continue. "); return 1; }
  503. log_debug("file $_[0] used by process with pid: $lockid");
  504. return 0;
  505. }
  506. #---------------------------------------------------------------------------------------------------------
  507. sub Add_Lock {
  508. if (!IsNotLocked($_[0])) { return 0; }
  509. my $lockfile = $_[0] . ".lock";
  510. open (FF,">$lockfile") or log_die "can't open file $lockfile: $!";
  511. flock(FF,2) or log_die "can't flock $lockfile: $!";
  512. print FF $$;
  513. close(FF);
  514. log_debug("Create lock file for $_[0]");
  515. return 1;
  516. }
  517. #---------------------------------------------------------------------------------------------------------
  518. sub Remove_Lock {
  519. if (!IsNotLocked($_[0])) { return 0; }
  520. my $lockfile = $_[0] . ".lock";
  521. if (! -e $lockfile) { return 1; }
  522. unlink $lockfile or return 0;
  523. log_debug("Lock file for $_[0] removed");
  524. return 1;
  525. }
  526. #---------------------------------------------------------------------------------------------------------
  527. sub DefHash {
  528. my $hash=$_[0];
  529. my $num_list = $_[1];
  530. my %num_keys;
  531. if ($num_list) {
  532. my @ret_num = split(' ',$num_list);
  533. %num_keys = map { $_, 1 } @ret_num;
  534. }
  535. foreach my $key (keys %$hash) {
  536. my $null_value = "";
  537. $null_value = 0 if (defined $num_keys{$key});
  538. $hash->{$key}=$null_value if (!defined($hash->{$key}));
  539. }
  540. return $hash;
  541. }
  542. #---------------------------------------------------------------------------------------------------------
  543. sub read_file {
  544. my $filename = shift;
  545. return if (!$filename);
  546. return if (!-e $filename);
  547. open (FF,"<$filename") or die "unable to open file $filename!" ;
  548. my @tmp=<FF>;
  549. close(FF);
  550. chomp(@tmp);
  551. return @tmp;
  552. }
  553. #---------------------------------------------------------------------------------------------------------
  554. sub uniq (\@) {
  555. my @tmp = @{(shift)};
  556. if (scalar(@tmp) eq 0) { return @tmp; }
  557. chomp(@tmp);
  558. my %newlist = map { $_, 1 } @tmp;
  559. return keys %newlist;
  560. }
  561. #---------------------------------------------------------------------------------------------------------
  562. sub strim {
  563. my $str=shift;
  564. return if (!$str);
  565. #$str =~ s/.*[^[:print:]]+//g;
  566. #$str =~ s/[^[:print:]]+//g;
  567. #$str =~ s/[^(a-z|A-Z|0-9|\:|\-|\s|\.)]//g;
  568. #$str =~ s/[:^print:]//g;
  569. $str =~ s/[^[:ascii:]]//g;
  570. $str =~ s/^\s+//g;
  571. $str =~ s/\s+$//g;
  572. return $str;
  573. }
  574. #---------------------------------------------------------------------------------------------------------
  575. sub trim {
  576. my $str=shift;
  577. return if (!$str);
  578. $str =~ s/\n/ /g;
  579. $str =~ s/^\s+//g;
  580. $str =~ s/\s+$//g;
  581. return $str;
  582. }
  583. #---------------------------------------------------------------------------------------------------------
  584. sub is_integer {
  585. defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
  586. }
  587. #---------------------------------------------------------------------------------------------------------
  588. sub is_float {
  589. defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/;
  590. }
  591. #---------------------------------------------------------------------------------------------------------
  592. sub run_in_parallel(\@) {
  593. my @commands = @{(shift)};
  594. my @result = ();
  595. return @result if (!@commands or !scalar(@commands));
  596. my $count = scalar(@commands);
  597. my $start = 0;
  598. while ($start<=$count-1) {
  599. my @run_list=();
  600. my $select = IO::Select->new();
  601. my $stop = $start + $parallel_process_count;
  602. $stop=$count-1 if ($stop >=$count);
  603. for (my $index = $start; $index <=$stop; $index++) {
  604. next if (!$commands[$index]);
  605. my $cmd=$commands[$index];
  606. log_info("Starting ".$cmd);
  607. my ($hchild, $hparent, $childid);
  608. socketpair($hchild, $hparent, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!";
  609. $childid = fork;
  610. die "cannot fork" if($childid == -1);
  611. # redirect child Input|Output
  612. unless($childid) {
  613. open STDIN, "<&", $hparent;
  614. open STDOUT, ">&", $hparent;
  615. open STDERR, ">&", $hparent;
  616. close $hparent;
  617. close $hchild;
  618. $select->remove($_) and close $_ for($select->handles);
  619. exec "/bin/nice -n 15 ".$cmd;
  620. }
  621. close $hparent;
  622. $select->add($hchild);
  623. }
  624. while (my @ready = $select->can_read) {
  625. next if (!@ready or !scalar(@ready));
  626. for my $read(@ready) {
  627. if($read->eof || $read->error) {
  628. # child exit
  629. $select->remove($read);
  630. close $read;
  631. next;
  632. }
  633. if(defined(my $str = <$read>)) {
  634. log_info("Read:".$str);
  635. push(@result,$str);
  636. }
  637. }
  638. }
  639. $start = $stop+1;
  640. }
  641. return (@result);
  642. }
  643. #---------------------------------------------------------------------------------
  644. sub translit {
  645. my $textline=shift;
  646. return if (!$textline);
  647. $textline =~ s/А/A/g; $textline =~ s/а/a/g;
  648. $textline =~ s/Б/B/g; $textline =~ s/б/b/g;
  649. $textline =~ s/В/V/g; $textline =~ s/в/v/g;
  650. $textline =~ s/Г/G/g; $textline =~ s/г/g/g;
  651. $textline =~ s/Д/D/g; $textline =~ s/д/d/g;
  652. $textline =~ s/Е/E/g; $textline =~ s/е/e/g;
  653. $textline =~ s/Ё/E/g; $textline =~ s/ё/e/g;
  654. $textline =~ s/Ж/Zh/g; $textline =~ s/ж/zh/g;
  655. $textline =~ s/З/Z/g; $textline =~ s/з/z/g;
  656. $textline =~ s/И/I/g; $textline =~ s/и/i/g;
  657. $textline =~ s/Й/I/g; $textline =~ s/й/i/g;
  658. $textline =~ s/К/K/g; $textline =~ s/к/k/g;
  659. $textline =~ s/Л/L/g; $textline =~ s/л/l/g;
  660. $textline =~ s/М/M/g; $textline =~ s/м/m/g;
  661. $textline =~ s/Н/N/g; $textline =~ s/н/n/g;
  662. $textline =~ s/О/O/g; $textline =~ s/о/o/g;
  663. $textline =~ s/П/P/g; $textline =~ s/п/p/g;
  664. $textline =~ s/Р/R/g; $textline =~ s/р/r/g;
  665. $textline =~ s/ТС/T-S/g; $textline =~ s/Тс/T-s/g; $textline =~ s/тс/t-s/g;
  666. $textline =~ s/С/S/g; $textline =~ s/с/s/g;
  667. $textline =~ s/Т/T/g; $textline =~ s/т/t/g;
  668. $textline =~ s/У/U/g; $textline =~ s/у/u/g;
  669. $textline =~ s/Ф/F/g; $textline =~ s/ф/f/g;
  670. $textline =~ s/Х/Kh/g; $textline =~ s/х/kh/g;
  671. $textline =~ s/Ц/Ts/g; $textline =~ s/ц/ts/g;
  672. $textline =~ s/Ч/Ch/g; $textline =~ s/ч/ch/g;
  673. $textline =~ s/Ш/Sh/g; $textline =~ s/ш/sh/g;
  674. $textline =~ s/Щ/Shch/g; $textline =~ s/щ/shch/g;
  675. #$textline =~ s/Ь/'/g; $textline =~ s/ь/'/g;
  676. #$textline =~ s/Ъ/''/g; $textline =~ s/ъ/''/g;
  677. $textline =~ s/Ь//g; $textline =~ s/ь//g;
  678. $textline =~ s/Ъ//g; $textline =~ s/ъ//g;
  679. $textline =~ s/Ы/Y/g; $textline =~ s/ы/y/g;
  680. $textline =~ s/Э/E/g; $textline =~ s/э/e/g;
  681. $textline =~ s/Ю/Yu/g; $textline =~ s/ю/yu/g;
  682. $textline =~ s/Я/Ya/g; $textline =~ s/я/ya/g;
  683. return $textline;
  684. }
  685. #---------------------------------------------------------------------------------
  686. sub netdev_set_auth {
  687. my $device = shift;
  688. $device->{login}=$config_ref{router_login} if (!$device->{login});
  689. $device->{password}=$config_ref{router_password} if (!$device->{password});
  690. $device->{password}=decrypt_string($device->{password});
  691. $device->{enable_password}='';
  692. #$device->{enable_password}=$device->{passowrd};
  693. $device->{proto} = 'ssh';
  694. $device->{proto} = 'telnet' if ($device->{protocol} eq '1');
  695. #patch for ssh
  696. if ($device->{proto} eq 'ssh' and exists $switch_auth{$device->{vendor_id}}{proto}) {
  697. #set specified ssh type
  698. if ($switch_auth{$device->{vendor_id}}{proto} =~/ssh/i) {
  699. $device->{proto} = $switch_auth{$device->{vendor_id}}{proto};
  700. }
  701. }
  702. $device->{port} = $device->{control_port} if ($device->{control_port});
  703. $device->{prompt} = qr/[\$#>]\s?$/;
  704. if (exists $switch_auth{$device->{vendor_id}}) {
  705. $device->{prompt} = $switch_auth{$device->{vendor_id}}{prompt} if ($switch_auth{$device->{vendor_id}}{prompt});
  706. }
  707. return $device;
  708. }
  709. #---------------------------------------------------------------------------------
  710. sub decrypt_string {
  711. my $crypted_string = shift;
  712. return if (!$crypted_string);
  713. my $cipher_handle = Crypt::CBC->new(
  714. {
  715. 'key' => $config_ref{encryption_key},
  716. 'cipher' => 'Cipher::AES',
  717. 'iv' => $config_ref{encryption_iv},
  718. 'literal_key' => 1,
  719. 'header' => 'none',
  720. keysize => 128 / 8
  721. }
  722. );
  723. my $result = $cipher_handle->decrypt(decode_base64($crypted_string));
  724. return $result;
  725. }
  726. #---------------------------------------------------------------------------------
  727. sub crypt_string {
  728. my $simple_string = shift;
  729. return if (!$simple_string);
  730. my $cipher_handle = Crypt::CBC->new(
  731. {
  732. 'key' => $config_ref{encryption_key},
  733. 'cipher' => 'Cipher::AES',
  734. 'iv' => $config_ref{encryption_iv},
  735. 'literal_key' => 1,
  736. 'header' => 'none',
  737. keysize => 128 / 8
  738. }
  739. );
  740. my $result = encode_base64($cipher_handle->encrypt($simple_string));
  741. return $result;
  742. }
  743. #---------------------------------------------------------------------------------------------------------------
  744. sub GetNowTime {
  745. my ($sec,$min,$hour,$day,$month,$year,$zone) = localtime(time());
  746. $month += 1;
  747. $year += 1900;
  748. my $now_str=sprintf "%04d-%02d-%02d %02d:%02d:%02d",$year,$month,$day,$hour,$min,$sec;
  749. return $now_str;
  750. }
  751. #---------------------------------------------------------------------------------------------------------------
  752. sub GetUnixTimeByStr {
  753. my $time_str = shift;
  754. $time_str =~s/\//-/g;
  755. $time_str = trim($time_str);
  756. my ($sec,$min,$hour,$day,$mon,$year) = (localtime())[0,1,2,3,4,5];
  757. $year+=1900;
  758. $mon++;
  759. if ($time_str =~/^([0-9]{2,4})\-([0-9]{1,2})-([0-9]{1,2})\s+/) {
  760. $year = $1; $mon = $2; $day = $3;
  761. }
  762. if ($time_str =~/([0-9]{1,2})\:([0-9]{1,2})\:([0-9]{1,2})$/) {
  763. $hour = $1; $min = $2; $sec = $3;
  764. }
  765. my $result = mktime($sec,$min,$hour,$day,$mon-1,$year-1900);
  766. return $result;
  767. }
  768. #---------------------------------------------------------------------------------------------------------------
  769. sub GetTimeStrByUnixTime {
  770. my $time = shift || time();
  771. my ($sec, $min, $hour, $mday, $mon, $year) = (localtime($time))[0,1,2,3,4,5];
  772. my $result = strftime("%Y-%m-%d %H:%M:%S",$sec, $min, $hour, $mday, $mon, $year);
  773. return $result;
  774. }
  775. #---------------------------------------------------------------------------------------------------------
  776. # Helper function for HTML escaping
  777. sub htmlspecialchars {
  778. my ($text) = @_;
  779. return '' unless defined $text;
  780. $text =~ s/&/&amp;/g;
  781. $text =~ s/</&lt;/g;
  782. $text =~ s/>/&gt;/g;
  783. $text =~ s/"/&quot;/g;
  784. $text =~ s/'/&#039;/g;
  785. return $text;
  786. }
  787. #---------------------------------------------------------------------------------
  788. #log_file($LOG_COMMON,"INFO:","----------------------------------------------------------------------------------------");
  789. #log_file($LOG_COMMON,"INFO:","Run script $0. Pid: $$ Pid file: $SPID.pid");
  790. #log_file($LOG_COMMON,"INFO:","User uid: $< Effective uid: $>");
  791. #log_file($LOG_COMMON,"INFO:","Status:");
  792. #log_file($LOG_COMMON,"INFO:","Logging enabled: $log_enable");
  793. #log_file($LOG_COMMON,"INFO:","Logging debug: $debug");
  794. 1;
  795. }