Альтернативный подход к перенаправлению вывода вашего терминала на терминал другого пользователя:
Выполнение на вашем терминале:
mkfifo foo; script -f foo
Используйте команду who, чтобы увидеть терминал другого пользователя; а на другом вашем терминале перенаправьте вывод на терминал другого пользователя с правами root:
cat foo >> /dev/pts/2
Когда процесс завершается, PPID его дочерних процессов устанавливается в 1 (принятие init), но PGID (идентификатор группы процессов) и SID (идентификатор сессии) не изменяются.
Дочерние процессы, вероятно, не меняют свою группу процессов, если только они не предназначены быть демонами. Если это не так, запустите тестируемый процесс в его собственной группе процессов. Вызовите setpgid(getpid(), getpid())
из вашего тестового фреймворка, после форка и перед вызовом execve
для выполнения тестируемой программы. Вызовите kill(-test_program_pid, 0)
(kill
с отрицательным аргументом pid
и значением сигнала 0), чтобы проверить, существует ли запущенный процесс с PGID test_program_pid
. Передайте SIGKILL
в качестве аргумента сигнала, чтобы убить их всех.
test_program_pid = fork();
if (test_program_pid) {
waitpid(test_program_pid, &status, 0);
if (kill(-test_program_pid, 0)) {
record_failue("some child processes were not terminated properly");
}
kill(-test_program_pid, SIGKILL);
} else {
setpgid(getpid(), getpid());
execve("/program/to/test", …);
}
Альтернативным методом может быть создание временного файла и открытие его в программе, которую вы тестируете, и нигде больше. Если программа вызывает execve
, убедитесь, что дескриптор файла открыт без флага O_CLOEXEC
(или вызовите fcntl(fd, FD_CLOEXEC, 0)
). Этот метод предполагает, что программа не идет и не закрывает файловые дескрипторы, которые она явно не использует. Затем вы можете выполнить fuser /temp/file
, чтобы перечислить процессы, у которых открыт этот файл, и fuser -k /temp/file
, чтобы убить их. Вариант этого подхода, который работает даже с программами, закрывающими неиспользуемые дескрипторы файлов, но предполагает, что программа не меняет свой текущий каталог, заключается в создании временного каталога и переходе в этот каталог для запуска программы.
Один из способов найти их - использовать ps -ef
, ища строки, в которых родительский идентификатор равен "1", например,
#!/bin/sh
orphans="$(ps -ef | awk '$3 == 1{ print $2; }')"
echo "Processes which might be orphans: $orphans"
Однако многие процессы имеют «1» в качестве родительского. Определить, какие из них вам интересны, лучше всего можно сделать, вспомнив, какие дочерние процессы были созданы вашей программой.
Если вам известно имя пользователя (и / или идентификатор пользователя ), под которым создаются эти процессы, вы можете исключить некоторые возможности. В первом столбце ps
может отображаться (в зависимости от типа системы) либо имя пользователя , либо соответствующий идентификатор пользователя . POSIX предлагает некоторую помощь здесь, но легко найти системы, которые отличаются - и документация отражает это:
-f
. С помощью всего лишь ps -ef
он показывает идентификатор процесса в первом столбце и не показывает идентификатор родительского процесса. Требуется опция -l
для отображения (вместо этого) идентификатора пользователя . ps -ef
или ps -efl
). -l
Solaris 10 показывает флаги процесса в первом и втором столбцах. Это упоминается в POSIX, хотя содержимое флагов не определено (поскольку содержимое различается на платформах Unix ). Как видите, для некоторого подмножества доступных систем ps -efl
даст «одинаковый» результат для первых трех столбцов. Для чего-то более общего вам нужно будет посмотреть на заголовок (первая строка) и определить, какой столбец содержит информацию, соответствующую владельцу процесса ( имя пользователя или идентификатор пользователя ). и идентификатор процесса и его родительский идентификатор процесса.
Для данной системы (зная используемые параметры для ps
и зная, следует ли сопоставить имя входа или идентификатор пользователя ), вы можете использовать awk
для соответствия , что и поле , например,
#!/bin/sh
orphans="$(ps -ef | awk -v user=$LOGNAME '($1 == user && $3 == 1){ print $2; }')"
echo "Processes which might be orphans: $orphans"
Здесь я использовал $ LOGNAME
, чтобы учесть использование POSIX термина имя пользователя , что может вводить в заблуждение (поскольку в принципе процессы могут осуществляться через sudo
, в то время как использование этого термина в POSIX подразумевает, что они пришли через «логин»).
Дополнительная литература: