Программирование в стандарте POSIX

       

Опрос и изменение атрибутов процессов


Для выдачи информации о процессах служит утилита ps:

ps [-aA] [-defl] [-G список_групп] [-o формат] ... [-p список_процессов] [-t список_терминалов] [-U список_пользователей] -g список_групп] [-n список_имен] [-u список_пользователей]

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

PID TTY TIME CMD 1594 ttyS4 00:00:02 sh 1645 ttyS4 00:00:00 sh 1654 ttyS4 00:02:45 rk.20.01 18356 ttyS4 00:00:00 prconecm 18357 ttyS4 00:00:00 sh 18358 ttyS4 00:00:00 ps

Листинг 7.1. Возможный результат использования утилиты ps. (html, txt)

Если нужна более подробная информация о более широком наборе процессов, следует пользоваться опциями. Перечислим наиболее употребительные из них.

-a

Выдать информацию обо всех процессах, ассоциированных с терминалами. Заметим, однако, что, во-первых, при получении информации о процессах контролируются права доступа (например, пользователю будут видны только порожденные им процессы), а во-вторых, по стандарту реализация может не включать в выдаваемый список лидеров сеансов.

-A

Выдать информацию обо всех процессах.

-G список_групп

Выдать информацию о процессах с заданными реальными идентификаторами групп.

-o формат

Выдать информацию о процессах в заданном формате.

-p список_процессов

Выдать информацию о процессах с заданными идентификаторами.

-t список_терминалов

Выдать информацию о процессах, ассоциированных с заданными терминалами. Способ задания терминалов зависит от реализации. Обычно указывается имя специального файла, например, ttyS4, или, если имя начинается с tty, просто S4.

-U список_пользователей

Выдать информацию о процессах с заданными реальными идентификаторами пользователей (они могут указываться и в виде входных имен).


Все перечисленные опции, кроме -o, ведают отбором процессов. Если задан целый ряд подобных опций, выводится информация обо всех специфицированных ими процессах.

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

Перечислим имена полей, которые могут указываться в выходном формате, и соответствующие им подразумеваемые заголовки.

ruser (RUSER)

Выдавать реальный идентификатор пользователя процесса (в символьной или числовой форме).

user (USER)

Действующий идентификатор пользователя процесса.

rgroup (RGROUP)

Реальный идентификатор группы процесса.

group (GROUP)

Действующий идентификатор группы процесса.

pid (PID)

Идентификатор процесса.

ppid (PPID)

Идентификатор родительского процесса.

pgid (PGID)

Идентификатор группы процессов.

pcpu (%CPU)

Процент процессорного времени, потребляемый процессом.

vsz (VSZ)

Размер процесса в (виртуальной) памяти (в килобайтных блоках).

nice (NI)

Число, используемое как рекомендация системе при планировании процессов. Меньшие значения соответствуют более приоритетным процессам.

etime (ELAPSED)

Астрономическое время, прошедшее с момента запуска процесса.

time (TIME)

Процессорное время, потребленное процессом.

tty (TT)

Имя управляющего терминала.

comm (COMMAND)

Имя выполняемой команды (argv [0]).

args (COMMAND)

Выполняемая командная строка.



Листинг 7.3. Фрагмент возможного результата использования утилиты ps.

Для опроса идентификаторов процесса, родительского процесса и группы процессов предусмотрены функции getpid() и getppid()   getpgrp() (см. листинг 7.4).

#include <unistd.h> pid_t getpid (void);

#include <unistd.h> pid_t getppid (void);



#include <unistd.h> pid_t getpgrp (void);

Листинг 7.4. getpid(), getppid() и getpgrp().

По стандарту эти функции всегда завершаются успешно, поэтому ошибочных кодов возврата не предусмотрено.

Для установки идентификатора группы процессов в целях управления заданиями предназначена функция setpgid() (см. листинг 7.5).

#include <unistd.h> int setpgid (pid_t pid, pid_t pgid);

Листинг 7.5. Описание функции setpgid().

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

В случае успешного завершения функции setpgid() (результат при этом равен нулю) идентификатор группы процессов устанавливается равным pgid для заданного аргументом pid процесса. Если значение pid равно нулю, установка производится для вызывающего процесса. А если значение pgid равно нулю, то в качестве идентификатора группы процессов используется идентификатор процесса, заданного аргументом pid.

Для создания сеанса и установки идентификатора группы процессов служит функция setsid() (см. листинг 7.6).

#include <unistd.h> pid_t setsid (void);

Листинг 7.6. Описание функции setsid().

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

Программа, показанная в листинге 7.7, служит примером использования (в том числе некорректного) описанных функций.


листинг 7.9). Как и getpid(), они всегда завершаются успешно.

#include <unistd.h> uid_t getuid (void);

#include <unistd.h> uid_t geteuid (void);

#include <unistd.h> gid_t getgid (void);

#include <unistd.h> gid_t getegid (void);

Листинг 7.9. Описание функций getuid(), geteuid(), getgid(), getegid().

Более сложный интерфейс имеет функция getgroups(), предназначенная для получения идентификаторов дополнительных групп вызывающего процесса (см. листинг 7.10). Эти идентификаторы (в их число может входить и действующий идентификатор группы процесса) помещаются в массив grouplist.

#include <unistd.h> int getgroups (int gidsetsize, gid_t grouplist []);

Листинг 7.10. Описание функции getgroups().

Аргумент gidsetsize задает число элементов в массиве grouplist, а реальное количество записанных идентификаторов групп возвращается в виде результата функции. Если в качестве значения gidsetsize задать нуль, getgroups() выдаст количество дополнительных групп, не модифицируя массив grouplist.

Переустановить действующий идентификатор пользователя вызывающего процесса позволяют функции setuid() и seteuid() (см. листинг 7.11). Операция разрешена, если реальный или сохраненный ПДП-идентификатор пользователя совпадает со значением аргумента uid. Помимо этого, обладающие соответствующими привилегиями процессы с помощью функции setuid() могут установить по значению uid все три идентификатора пользователя процесса – реальный, действующий и сохраненный.

#include <unistd.h> int setuid (uid_t uid);

#include <unistd.h> int seteuid (uid_t uid);

Листинг 7.11. Описание функций setuid() и seteuid().

Для непривилегированных процессов по соображениям мобильности рекомендуется использование функции seteuid().

Аналогичные функции для переустановки идентификаторов группы процесса показаны в листинге 7.12.

#include <unistd.h> int setgid (gid_t gid);

#include <unistd.h> int setegid (gid_t gid);

Листинг 7.12. Описание функций setgid() и setegid().



Листинг 7.13. Пример использования функций опроса и изменения идентификаторов пользователя процесса.

Если эту программу запустить от имени обычного пользователя, результат может выглядеть так, как показано в листинге 7.14.

Идентификаторы пользователя текущего процесса: реальный: 108, действующий: 108 Идентификаторы группы текущего процесса: реальный: 3, действующий: 3 Количество дополнительных групп текущего процесса: 1 Идентификаторы дополнительных групп текущего процесса: 3 setuid (1): Operation not permitted Идентификаторы пользователя текущего процесса после первой смены: реальный: 108, действующий: 108 Идентификаторы пользователя текущего процесса после второй смены: реальный: 108, действующий: 108 seteuid (1): Operation not permitted Идентификаторы пользователя текущего процесса после третьей смены: реальный: 108, действующий: 108

Листинг 7.14. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени обычного пользователя.

После запуска той же программы от имени суперпользователя может получиться результат, показанный в листинге 7.15.

Идентификаторы пользователя текущего процесса: реальный: 0, действующий: 0 Идентификаторы группы текущего процесса: реальный: 0, действующий: 0 Количество дополнительных групп текущего процесса: 7 Идентификаторы дополнительных групп текущего процесса: 0 1 2 3 4 6 10 Идентификаторы пользователя текущего процесса после первой смены: реальный: 1, действующий: 1 setuid (uid): Operation not permitted Идентификаторы пользователя текущего процесса после второй смены: реальный: 1, действующий: 1 Идентификаторы пользователя текущего процесса после третьей смены: реальный: 1, действующий: 1

Листинг 7.15. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени суперпользователя.

Утерять статус суперпользователя легко, а вернуть трудно...

Наконец, сделаем владельцем выполнимого файла рассматриваемой программы пользователя с идентификатором 1, то же проделаем с владеющей группой, взведем в режиме этого файла биты ПДИП и ПДИГ(на ОС Linux можно воспользоваться командой chmod ug+s) и вновь запустим его от имени обычного пользователя (см.

Содержание раздела