Лабораторная работа "Управление процессами" - efanov/mephi GitHub Wiki
- Цель
- Задание
- Мониторинг процессов
- Механизм сигналов
- Работа процесса с файлами
- Изучение системных вызовов
- Порядок защиты лабораторной работы
Изучить свойства процессов и средства управления процессами.
После выполнения лабораторной студент должен знать следующие аспекты процессов:
- Командный интерфейс мониторинга процессов.
- Возможности файловой системы procfs.
- Механизм заданий (jobs). Выполнение процесса в основном и фоновом режимах.
- Взаимодействие процесса с виртуальной файловой системой.
- Средства взаимодействия процессов (механизм сигналов).
- Жизненный цикл процесса (системные вызовы fork->exec->wait->exit).
Команды, изучаемые в лабораторной работе: ps
, top
, pgrep
, pstree
, w
, uptime
, jobs
, fg
, bg
, kill
, killall
, pkill
, trap
.
Системные вызовы, изучаемые в лабораторной работе: fork(), execve(), wait(), exit(), sigaction().
-
Выведите информацию обо всех процессах в системе, используя стандартный синтаксис:
$ ps -e $ ps -ef $ ps -eF $ ps -ely
-
Выведите информацию обо всех процессах в системе, используя синтаксис BSD:
$ ps ax $ ps axu
-
Выведите информацию обо всех процессах в системе в виде дерева:
$ ps -ejH $ ps axjf
-
Выведите информацию о легковесных процессах:
$ ps -eLf $ ps axms
-
Выведите атрибуты безопасности процессов разными способами:
$ ps -eo euser,ruser,suser,fuser,f,comm,label $ ps axZ $ ps -eM
-
Выведите информацию о процессах, выполняющихся от имени пользователя root (real & effective ID), в пользовательском формате:
$ ps -U root -u root u
-
Выведите информацию о процессах в пользовательском формате:
$ ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm $ ps axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm $ ps -Ao pid,tt,user,fname,tmout,f,wchan
-
Выведите только идентификаторы процессов с именем systemd:
$ ps -C systemd -o pid=
-
Выведите только имя процесса с заданным идентификатором PID:
$ ps -q <PID> -o comm=
Обратите внимание: в переменной $ хранится PID текущего процесса. Поэтому вместо конструкции $$ bash подставит собственный PID.
-
Изучите содержимое файла /proc/version и сравните с выводом команды uname -a.
-
Изучите и сравните содержимое файлов /proc/meminfo и /sys/devices/system/node/node0/meminfo, и вывод команды free.
-
Изучите содержимое файла /proc/cpuinfo. Определите количество ядер.
-
Изучите содержимое файла /proc/uptime и сравните с выводом команды uptime.
-
Изучите специальную символьную ссылку /proc/self, которая указывает на директорию текущего (self) процесса. Объясните результаты.
$ echo $$ 3203 $ ls -l /proc/self lrwxrwxrwx. 1 root root 0 Oct 13 21:42 /proc/self -> 12485
-
Изучите содержимое файла /proc//status.
$ cat /proc/$$/status Name: bash Umask: 0002 State: S (sleeping) Tgid: 8266 Ngid: 0 Pid: 8266 PPid: 8260 TracerPid: 0 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 FDSize: 256 Groups: 10 1000 ...
-
Изучите содержимое файла /proc//stat. Формат вывода можно посмотреть в исходном коде ядра Linux в файле /fs/proc/array.c в функции do_task_stat(). Пример:
$ read pid tcomm state other < /proc/$$/stat $ echo "Процесс $pid $tcomm находится в состоянии $state" Процесс 3203 (bash) находится в состоянии R
-
Откройте два окна терминала (левый и правый).
-
В левом окне запустите бесконечный процесс, который с интервалом в одну секунду будет писать строку AAA в файл test.out в домашнем каталоге.
$ ( while true; do printf "AAA %d " $$ >> ~/test.out; sleep 1; done )
-
В правом окне наблюдайте за работой процесса.
$ tail -f ~/test.out
-
В левом окне остановите процесс. BASH вернет номер задания в квадратных скобках. Убедитесь, что процесс перестал писать в файл. Обратите внимание, что изменилось состояние процесса (ps j).
$ Ctrl+z
-
В левом окне выведите список заданий. Знаком + помечено текущее задание. Определите состояние процесса. Запустите задание в фоновом режиме. Убедитесь, что процесс снова продолжил писать в файл. Определите состояние процесса ещё раз.
$ jobs $ ps j $ bg $ jobs $ ps j
-
В левом окне запустите второй бесконечный процесс в фоновом режиме, который с интервалом в одну секунду будет писать строку UUU в файл test.out в домашнем каталоге. Команда должна быть заключена в круглые скобки и заканчиваться знаком &.
$ ( while true; do printf "UUU %d " $$ >> ~/test.out; sleep 1; done ) &
-
В левом окне выведите список заданий. Убедитесь, что теперь два процесса пишут в файл.
$ jobs
-
В левом окне завершите процессы.
$ fg %номер $ Ctrl+c $ fg %номер $ Ctrl+c
-
В правом окне завершите команду tail.
-
Откройте два окна терминала (левый и правый).
-
В левом окне запустите два бесконечных процесса, которые с интервалом в одну секунду будут писать строки в файл test.out в домашнем каталоге. Выведите список заданий (наблюдайте Running). Определите состояние процессов.
$ ( while true; do printf "AAA %d " $$ >> ~/test.out; sleep 1; done ) & $ ( while true; do printf "UUU %d " $$ >> ~/test.out; sleep 1; done ) & $ jobs $ ps j
-
В правом окне наблюдайте за работой процессов.
$ tail -f ~/test.out
-
В левом окне остановите первый процесс (задание "AAA"). Выведите список заданий (наблюдайте Stopped).
$ kill -SIGSTOP %1 $ jobs
-
В левом окне завершите второй процесс (задание "UUU"). Выведите список заданий (наблюдайте Terminated).
$ kill -SIGTERM %2 $ jobs
-
В левом окне завершите процесс.
$ fg $ Ctrl+c
-
В правом окне завершите команду tail.
Команда trap позволяет установить обработчик на сигнал. Опция -l выводит список сигналов. Опция -p выводит установленные обработчики сигналов.
-
Выведите список сигналов.
$ trap -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
-
Запустите дочерний shell и установите обработчик сигнала EXIT (0, который посылается нажатием Ctrl+d).
$ sh sh-4.3$ trap 'echo Завершение работы...; sleep 2' EXIT sh-4.3$ trap -p EXIT trap -- 'echo Завершение работы...; sleep 2' EXIT
-
Завершите shell.
$ Ctrl+d
-
Наблюдайте перехват сигнала и вызов обработчика.
-
Создайте сценарий.
$ cat test-trap.sh #!/bin/bash declare -i i=0 trap 'echo "Аварийное завершение..."; exit 1' SIGINT while [ $i -lt 100 ] do (( i++ )) echo $i sleep 1 done
-
Запустите сценарий.
$ chmod +x test-trap.sh $ ./test-trap.sh
-
Завершите сценарий. Объясните результаты.
$ Ctrl+C
-
Изучите различные формы обращения к файловым дескрипторам и потокам stdin, stdout, stderr.
$ ls -l /dev/std* lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stderr -> /proc/self/fd/2 lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stdin -> /proc/self/fd/0 lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stdout -> /proc/self/fd/1 $ ls -l /dev/fd/ total 0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 2 -> /dev/pts/0 lr-x------. 1 defanov defanov 64 Oct 14 00:31 3 -> /proc/13123/fd
-
Изучите список открытых файлов процесса. Определите потоки stdin, stdout, stderr.
$ ls -l /proc/self/fd total 0 lrwx------. 1 defanov defanov 64 Oct 14 00:07 0 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:07 1 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:07 2 -> /dev/pts/0 lr-x------. 1 defanov defanov 64 Oct 14 00:07 3 -> /proc/12898/fd
-
Перенаправьте потоки stdout и stderr в файлы. Объясните результаты.
$ ls -l /proc/self/fd > /tmp/ls.out 2> /tmp/ls.err $ cat /tmp/ls.out total 0 lrwx------. 1 defanov defanov 64 Oct 14 00:09 0 -> /dev/pts/0 l-wx------. 1 defanov defanov 64 Oct 14 00:09 1 -> /tmp/ls.out l-wx------. 1 defanov defanov 64 Oct 14 00:09 2 -> /tmp/ls.err lr-x------. 1 defanov defanov 64 Oct 14 00:09 3 -> /proc/12915/fd
-
Перенаправьте поток stdin. Объясните права доступа.
-
Откройте два окна терминала (левый и правый).
-
В левом окне (TTY == pts/0) запустите конвейер (неименованный канал), перенаправьте потоки stdout и stderr в файлы в домашнем каталоге.
$ ( cat | head ) > ~/test.out 2> ~/test.err
-
В правом окне (TTY == pts/1) выведите дескрипторы открытых файлов процессов bash, cat и head.
$ ps j --forest PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 47414 47418 47418 8758 pts/1 47792 S 1001 0:00 -bash 47418 47792 47792 8758 pts/1 47792 R+ 1001 0:00 \_ ps j --forest 47199 47203 47203 6634 pts/0 47771 S 1001 0:00 -bash 47203 47771 47771 6634 pts/0 47771 S+ 1001 0:00 \_ -bash 47771 47772 47771 6634 pts/0 47771 S+ 1001 0:00 \_ cat 47771 47773 47771 6634 pts/0 47771 S+ 1001 0:00 \_ head $ ls -l /proc/47771/fd total 0 lrwx------. 1 user1 user1 64 Nov 22 21:45 0 -> /dev/pts/0 l-wx------. 1 user1 user1 64 Nov 22 21:45 1 -> /home/user1/test.out l-wx------. 1 user1 user1 64 Nov 22 21:45 2 -> /home/user1/test.err $ ls -l /proc/47772/fd total 0 lrwx------. 1 user1 user1 64 Nov 22 21:45 0 -> /dev/pts/0 l-wx------. 1 user1 user1 64 Nov 22 21:45 1 -> 'pipe:[611050]' l-wx------. 1 user1 user1 64 Nov 22 21:45 2 -> /home/user1/test.err $ ls -l /proc/47773/fd total 0 lr-x------. 1 user1 user1 64 Nov 22 21:45 0 -> 'pipe:[611050]' l-wx------. 1 user1 user1 64 Nov 22 21:45 1 -> /home/user1/test.out l-wx------. 1 user1 user1 64 Nov 22 21:45 2 -> /home/user1/test.err
-
Изучите как поток stdout процесса cat связан с потоком stdin процесса head. Обратите внимание на то, что конструкция
( ... | ... )
выполняется в отдельном шелле. Процессы bash, cat и head являются родственными процессами (PID одного равен PPID двух других) и принадлежат к одной группе процессов (PGID == 47771), а лидером группы является процесс bash (PID == PGID == 47771). -
В левом окне завершите процессы.
-
В левом окне создайте именованный канал (FIFO). Какой тип у файла ~/fifo1?
$ mkfifo ~/fifo1
-
В левом окне запустите команду cat с перенаправлением вывода в созданный канал.
$ cat > ~/fifo1
-
В правом окне запустите команду cat с перенаправлением ввода из канала.
$ cat < ~/fifo1
-
Откройте ещё одно (третье) окно терминала и запустите в нём команду cat с перенаправлением ввода из канала.
$ cat < ~/fifo1
-
В левом окне вводите строки текста и наблюдайте вывод в двух других окнах. Объясните результаты.
-
Изучите дескрипторы открытых файлов процессов cat. Как связаны их потоки stdout и stdin?
-
Обратите внимание на то, что через именованные каналы могут общаться неродственные процессы. Объясните почему?
-
Организуйте чтение из канала в бесконечном цикле while с помощью команды read.
-
Завершите процессы. Закройте окна терминалов.
Команда exec используется для двух целей: запуск программ и открытие файлов.
-
Запустите дочерний shell и заместите коды порожденного процесса кодами команды ps -l. Обратите внимание на то, что PID процесса sh совпадает с PID процесса ps (13028). Объясните результаты.
$ sh sh-4.3$ ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 1000 3203 3197 0 80 0 - 29691 wait pts/0 00:00:00 bash 0 S 1000 13028 3203 0 80 0 - 28960 wait pts/0 00:00:00 sh 0 R 1000 13030 13028 0 80 0 - 34450 - pts/0 00:00:00 ps sh-4.3$ exec ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 1000 3203 3197 0 80 0 - 29691 wait pts/0 00:00:00 bash 0 R 1000 13028 3203 0 80 0 - 34450 - pts/0 00:00:00 ps $ ps -l F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 0 S 1000 3203 3197 0 80 0 - 29691 wait pts/0 00:00:00 bash 0 R 1000 13034 3203 0 80 0 - 34450 - pts/0 00:00:00 ps
-
Исследуйте работу процесса с файлами на примере bash. Откройте файл ~/test.out на запись и свяжите его с дескриптором 3.
$ exec 3> ~/test.out $ ls -l /proc/$$/fd total 0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0 l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out $ echo Test Test $ echo Test3 >&3 $ cat ~/test.out Test3 $ echo Test333 >&3 $ cat ~/test.out Test3 Test333
-
Выведите информацию об открытых файлах процесса bash. Объясните позицию указателя чтения/записи (pos: 14).
$ echo $$ 3203 $ ls -l /proc/3203/fdinfo/ total 0 -r--------. 1 defanov defanov 0 Oct 13 21:30 0 -r--------. 1 defanov defanov 0 Oct 13 21:30 1 -r--------. 1 defanov defanov 0 Oct 13 21:30 2 -r--------. 1 defanov defanov 0 Oct 13 21:30 255 -r--------. 1 defanov defanov 0 Oct 14 00:40 3 $ cat /proc/3203/fdinfo/3 pos: 14 flags: 0100001 mnt_id: 82
-
Откройте файл ~/test.out на чтение и свяжите его с дескриптором 4.
$ exec 4< ~/test.out $ ls -l /proc/$$/fd total 0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0 l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out lr-x------. 1 defanov defanov 64 Oct 14 00:54 4 -> /home/defanov/test.out $ cat ~/test.out Test3 Test333 $ cat <&4 Test3 Test333 $ cat ~/test.out Test3 Test333 $ cat <&4 $ $ echo Test4 >&3 $ cat ~/test.out Test3 Test333 Test4 $ cat <&4 Test4 $ cat <&4 $
-
Удалите файл ~/test.out.
$ rm ~/test.out $ ls -l /proc/$$/fd total 0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0 lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0 l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out (deleted) lr-x------. 1 defanov defanov 64 Oct 14 00:54 4 -> /home/defanov/test.out (deleted)
-
Попробуйте вывести содержимое файла ~/test.out командой cat, используя два способа обращения к файлу: через дескриптор и через имя. Объясните результат.
-
На портале https://github.com создайте fork репозитория https://github.com/efanov/linux-textbook.
-
Склонируйте полученный репозиторий на компьютер:
$ git clone https://github.com/<ваш_login>/linux-textbook
-
Изучите программу p_wait.c. Программа создает процесс-потомка. Если программа запускается без аргумента, то процесс-потомок приостанавливает свое выполнение с помощью системного вызова pause(), чтобы пользователь смог послать ему сигнал. Если программа запускается с аргументом, то процесс-потомок немедленно завершается, передавая значение аргумента в качестве кода возврата. Процесс-родитель в цикле выполняет системный вызов waitpid(), чтобы отслеживать состояние процесса-потомка. С помощью макросов W*() он анализирует значение полученного статуса от процесса-потомка.
-
Выполните компиляцию и запуск программы. Пример работы с программой:
$ gcc p_wait.c -o p_wait $ ./p_wait & Child PID is 32360 [1] 32359 $ kill -STOP 32360 stopped by signal 19 $ kill -CONT 32360 continued $ kill -TERM 32360 killed by signal 15 [1]+ Done ./p_wait
-
Объясните полученные результаты.
-
На портале https://github.com создайте fork репозитория https://github.com/efanov/mephi.
-
Склонируйте полученный репозиторий на компьютер:
$ git clone https://github.com/<ваш_login>/mephi
-
Изучите содержимое директории processes. Программа p_execve.c запускает (выполняет exec) другую программу, путь к которой передаётся через аргумент командной строки. Программа p_print_argv_env.c предназначена для выполнения программой p_execve.c, она выводит аргументы, с которыми она запущена, и переменные окружения.
-
Выполните компиляцию и запуск программ:
$ gcc p_execve.c -o p_execve $ gcc p_print_argv_env.c -o p_print_argv_env $ ./p_execve ./p_print_argv_env argv[0] = p_print_argv_env argv[1] = Russia argv[2] = Moscow environ: University=MEPhI
-
Объясните полученные результаты.
-
Изучите содержимое директории signals. Программа p_sigaction.c с помощью системного вызова sigaction() изменяет диспозицию сигнала SIGINT.
-
Выполните компиляцию и запуск программы. Отправляйте процессу сигнал SIGINT, нажимая на клавиатуре Ctrl+C. Для завершения процесса нажмите **Ctrl+**.
$ make $ ./p_sigaction ./p_sigaction: PID is 54715 ^CReceived signal 2 (Interrupt) ^CReceived signal 2 (Interrupt) ^CReceived signal 2 (Interrupt) ^\Quit (core dumped) $
-
Объясните полученные результаты.
-
Запустите программу ещё раз.
-
Остановите процесс.
-
Отправьте процессу сигнал SIGINT из командной строки.
-
Изучите дескриптор процесса.
-
Завершите процесс.
-
Пример:
$ ./p_sigaction ./p_sigaction: PID is 54715 ./p_sigaction: PID is 60922 ^Z [1]+ Stopped ./p_sigaction $ kill -SIGINT 60922 $ cat /proc/60922/status Name: p_sigaction Umask: 0002 State: T (stopped) Pid: 60922 ... SigPnd: 0000000000000000 ShdPnd: 0000000000000002 SigBlk: 0000000000000000 SigIgn: 0000000000000000 SigCgt: 0000000000000002 ... $ fg ./p_sigaction Received signal 2 (Interrupt) ^\Quit (core dumped) $
-
Измените программу таким образом, чтобы сигнал SIGINT игнорировался процессом.
-
Объясните полученные результаты.
-
Найти в системе все процессы, у которых различаются реальные и эффективные пользовательские идентификаторы.
-
Для обнаруженных процессов вывести имя программы.
Для тестирования можно использовать программу passwd.
Для защиты работы необходимо ответить на вопросы по выполненным заданиям.