Использование модуля Proc ProcessTable



Использование модуля Proc::ProcessTable

Дэниел Дж. Урист (Daniel J. Urist) (с помощью нескольких добровольцев) написал модуль Proc: :ProcessTable, предоставляющий единый интерфейс к таблице процессов для всех основных вариантов операционной системы Unix. Он скрывает от вас причуды различных реализаций /ргос и kmem, позволяя писать более переносимые программы.

Просто загрузите модуль, создайте объект Ргос: :ProcessTable: :Proces-и используйте методы этого объекта:

use Proc: :ProcessTable;

$tobj = new Proc: : ProcessTable;

Этот объект использует механизм связанных переменных (tied variable) для представления текущего состояния системы. Для обновления! этого объекта не требуется вызывать специальную функцию - он перечитывает таблицу процессов при каждом обращении к нему. Это похоже на хэш %Process, знакомый нам по обсуждению модуля Мае : Р ses ранее в этой главе.

Чтобы получить нужную информацию, следует вызвать метод

: : Sproctable = $tobj->table();

table() возвращает ссылку на массив, элементы которого представляют собой ссылки на объекты процессов. Каждый из этих объектов имеет свой собственный набор методов, возвращающих информацию об этом процессе. Например, вот как можно получить список идентификаторов процессов и их владельцев:

use Proc::ProcessTable:

Stobj = new Proc::ProcessTable:

Sproctable = $tobj->table(); for (ia>$proctable){

print $_->pid."\t". getpwuid($_->uid)."\n";

}

Список методов, доступных в вашей операционной системе, можно получить при помощи метода fields() объекта Proc: : ProcessTable (т.е. $tobj).

В Proc:: ProcessTable также есть три дополнительных метода у каждого объекта процесса: kill(), priorityO и pgrp(), которые являются всего лишь интерфейсом к встроенным функциям, упомянутым в начале этого раздела.

Чтобы опять вернуться к общей задаче, посмотрим на применение способов контроля над процессами. Мы начали изучать управление процессами в контексте действий пользователя, поэтому сейчас рассмотрим несколько маленьких сценариев, посвященных этим действиям. В примерах мы будем использовать Proc:: ProcessTable в Unix, но сами идеи не зависят от операционной системы.

Первый пример из документации по Proc: : ProcessTable: use Proc::ProcessTable;

$t = new Proc::ProcessTable; foreach $p ((5>{$t->table}){

if ($p->pctmem > 95){ $p->kill(9);

}

}

Эта программа «отстреливает» все процессы, занимающие 95% памяти в тех вариантах операционной системы Unix, где поддерживается метод pctmem() (а он поддерживается в большинстве случаев). В таком виде пример, вероятно, слишком «безжалостен», чтобы использовать его в реальной жизни. Было бы благоразумно добавить перед командой kill() что-то подобное:

print "собираемся убрят;. " Sn-^pid. "\t". get. owuid($p->uid).

"Vi": print "выполнять9 (yes'''i'0 " chomp($ans = о):

next unless (Sans eq "yes"):

Здесь может возникнуть состояние перехвата: не исключено, что во время задержки, вызванной вопросом к пользователю, состояние системы изменится. Учитывая, что мы в данном случае работаем только с «большими» процессами, которые вряд ли меняют свое состояние в течение короткого времени, такой вариант, скорее всего, пройдет нормально. Если вы хотите подойти к этому вопросу более педантично, вам, наверное, стоит получить сначала список процессов, которые вы хотите завершить, спросить пользователя, а затем проверить еще раз состояние таблицы процессов и только потом их завершать.

Бывают случаи, когда завершение процесса - это слишком легкая расплата. Иногда важно засечь, что процесс действительно работает, чтобы предпринять необходимые меры (скажем, поставить пользователя на место). Например, политика нашего сайта запрещает применять IRC-роботы. Роботы - это процессы-демоны, которые соединяются с IRC-серверами и выполняют автоматические действия. И хотя роботы могут использоваться в благих целях, в настоящее время они, в основном, играют асоциальную роль в IRC. Кроме того, мы обращали внимание на взлом системы безопасности из-за того, что первое (и часто единственное), что делал взломщик, — это запускал IRC-робота. Короче говоря, нам важно заметить присутствие таких процессов, а не завершать их работу.

Чаще других сейчас используется робот под названием eggdrop. Выяснить, запущен ли в системе процесс с таким именем, можно при помощи следующей программы:

use Proc::ProcessTable;

open(LOG, "»$logf ile") or die

"Невозможно открыть журнал для дозаписи:

$t = new Proc::ProcessTable; foreach $p (@{$t->table})

{ if ($p->fname() =" /eggdrop/i){ print LOG time."\t".

getpwuid($p->uid).

"\t".$p->fname()."\n": >

}

close(LOG);

Тот, кто подумает: «Эта программа не так уж и хороша! Все, что нужно сделать, чтобы ускользнуть от этой проверки, так это всего лишь переименовать исполняемый файл», будет абсолютно прав. Мы попытаемся написать менее простодушный код, ищущий роботов, в самом последнем разделе этой главы.

А пока рассмотрим еще один пример, в котором Perl помогает управлять процессами пользователей. До сих пор все наши примеры касались отрицательных явлений. Рассмотренные программы имели дело со злонамеренными или жадными к ресурсам процессами. Теперь посмотрим на что-нибудь более жизнерадостное.

Существуют ситуации, когда системному администратору необходимо узнать, какие программы применяются пользователями в системе. Иногда это необходимо сделать для программного обеспечения, лицензия которого запрещает его одновременное использование сверхнормативным числом потребителей. В таких случаях обычно применяется специальный механизм. Иногда подобные сведения необходимы, чтобы иметь возможность перейти на другую систему. Если вы переносите пользователей с одной системы на другую, вам необходимо убедиться, что все программы, работающие на старом месте, будут доступны и на новом.

Один подход к решению этой задачи - заменить каждую доступную пользователям исполняемую программу, не входящую в состав операционной системы, на оболочку, которая сначала запишет, какая программа была вызвана, а затем и запустит ее. Это сложно реализовать, если в системе доступно множество программ. Кроме того, есть и побочный эффект - запуск каждой программы требует большего времени.

Если точность не важна и достаточно знать только приблизительную оценку набора работающих программ, можно применить Ргос::Рго-cessTable. Ниже приведена программа, которая активизируется каждые пять минут и проверяет состояние текущих процессов. Она просто ведет учет всех найденных имен процессов, причем те процессы, которые встречались в предыдущий раз, она во второй раз не учитывает. Ежечасно программа записывает результаты и начинает подсчет заново. Пятиминутное ожидание объясняется тем, что обход таблицы процессов является ресурсоемкой операцией (обычно), а мы хотим, чтобы эта программа как можно меньше загружала систему:

use Proc::ProcessTable;

Sinterval = 600;

5 минут перерыва

Spartofhour = 0; (f отмечаем позицию часа, в которой мы находимся

Stop] = new Proc: : ProcessTabie;

создаем човый объект

tt вечный цикл, сбор данных каждые Sintervai секунд

№ и сброс этих данных один раз в час

while(1){

ucollectstats;

&dumpandreset if (Spartofhour >= 3600);

sleep($interval), }

сбор статистики по пролессу sub collectsrars ( my($process);

foreach Sprocess (@{$tobj->table}){

мы должны игнорировать себя next if ($process->pid() == $$);

сохраняем информацию о процессе для следующего запуска

push(@last,Sprocess->pid(),$process->fname());

игнорируем процесс, если мы его уже видели

next if ($last{$process->pid()} eq $process->fname());

если не видели, запоминаем его

$collection{$process->fname()}++; }

и устанавливаем хэш %last, используя текущую таблицу %last = ©last;

Spartofhour += $interval; }

выводим результаты и сбрасываем значения счетчиков

sub dumpandreset{

print scalar localtime(time). C'-"x50),"\n";

for (sort reverse_value_sort keys %collection){ write;

undef %collection; Spartofhour = 0; }

(обратная) сортировка no значениям хэша %collection и по

именам ключей

sub reverse_value_sort{

return $collection{$b} <=> $collection{$a} || $a cmp $b;

}

format STDOUT = @««««« »»

$_, $collection{$._}

format STDOUT_TOP = Name Count

Существует множество способов улучшить эту программу. Она могла бы отслеживать процессы для каждого пользователя (т. е. записывать один экземпляр вызова программы для каждого пользователя), собирать ежедневную статистику, выводить информацию в виде диаграммы и т. д. Все зависит только от того, где вы хотите ее применять.



- Начало - - Назад - - Вперед -