Файл дескриптор в Linux с примерами / Хабр
Однажды, на одном интервью меня спросили, что ты будешь делать, если обнаружишь неработающий сервис из-за того, что на диске закончилось место?
Конечно же я ответил, что посмотрю, чем занято это место и если возможно, то почищу место.
Тогда интервьюер спросил, а что если на разделе нет свободного места, но и файлов, которые бы занимали все место, ты тоже не видишь?
На это я сказал, что всегда можно посмотреть открытые файл дескрипторы, например командой lsof и понять какое приложение заняло все доступное место, а дальше можно действовать по обстоятельствам, в зависимости от того, нужны ли данные.
Интервьюер прервал меня на последнем слове, дополнив свой вопрос: «Предположим, что данные нам не нужны, это просто дебаг лог, но приложение не работает из-за того, что не может записать дебаг»?
«окей», — ответил я, «мы можем выключить дебаг в конфиге приложения и перезапустить его».
«ну хорошо», сказал я, «если мы не можем перезапускать приложение и данные нам не важны, то мы можем просто очистить этот открытый файл через файл дескриптор, даже если мы его не видим в команде ls на файловой системе».
Интервьюер остался доволен, а я нет.
Тогда я подумал, почему человек, проверяющий мои знания, не копает глубже? А что, если данные все-таки важны? Что если мы не можем перезапускать процесс, и при этом этот процесс пишет на файловую систему в раздел, на котором нет свободного места? Что если мы не можем потерять не только уже записанные данные, но и те данные, что этот процесс пишет или пытается записать?
Тузик
В начале моей карьеры я пытался создать небольшое приложение, в котором нужно было хранить информацию о пользователях.
Файл дескриптор
Проблема файла и программы, работающей с этим файлом, примерно такая же как нашей собаки и человека. Предположим я открыл файл под именем ivan.txt и начал в него записывать слово tuzik, но успел записать только первую букву «t» в файл, и этот файл был кем-то переименован, например в olya.txt. Но файл остался тем же самым, и я все еще хочу записать в него своего тузика. Каждый раз при открытии файла системным вызовом open в любом языке программирования я получаю уникальный ID, который указывает мне на файл, этот ID и есть файл дескриптор. И совершенно не важно, что и кто делает с этим файлом дальше, его могут удалить, его могут переименовать, ему могут поменять владельца или забрать права на чтение и запись, я все равно буду иметь к нему доступ, потому что на момент открытия файла у меня были права для его чтения и/или записи и я успел начать с ним работать, а значит должен продолжать это делать.
В Linux библиотека libc открывает для каждого запущенного приложения(процесса) 3 файл дескриптора, с номерами 0,1,2. Больше информации вы можете найти по ссылкам man stdio и man stdout
- Файл дескриптор 0 называется STDIN и ассоциируется с вводом данных у приложения
- Файл дескриптор 1 называется STDOUT и используется приложениями для вывода данных, например командами print
- Файл дескриптор 2 называется STDERR и используется приложениями для вывода данных, сообщающих об ошибке
Если в вашей программе вы откроете какой-либо файл на чтение или запись, то скорее всего вы получите первый свободный ID и это будет номер 3.
Список файл дескрипторов можно посмотреть у любого процесса, если вы знаете его PID.
Например, откроем консоль с bash и посмотрим PID нашего процесса
[user@localhost ]$ echo $$ 15771
Во второй консоли запустим
[user@localhost ]$ ls -lah /proc/15771/fd/ total 0 dr-x------ 2 user user 0 Oct 7 15:42 . dr-xr-xr-x 9 user user 0 Oct 7 15:42 .. lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
Файл дескриптор с номером 255 можете смело игнорировать в рамках данной статьи, он был открыт для своих нужд уже самим bash, а не прилинкованной библиотекой.
Сейчас все 3 файл дескриптора связаны с устройством псевдотерминала /dev/pts, но мы все равно можем ими манипулировать, например запустим во второй консоли
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
И в первой консоли мы увидим
[user@localhost ]$ hello world
Redirect и Pipe
Вы можете легко переопределить эти 3 файл дескриптора в любом процессе, в том числе и в bash, например через трубу(pipe), соединяющую два процесса, смотрим
[user@localhost ]$ cat /dev/zero | sleep 10000
Вы можете сами запустить эту команду с strace -f и увидеть, что происходит внутри, но я вкратце расскажу.
Наш родительский процесс bash с PID 15771 парсит нашу команду и понимает сколько именно команд мы хотим запустить, в нашем случае их две: cat и sleep. Bash знает что ему нужно создать два дочерних процесса, и объединить их одной трубой. Итого bash потребуется 2 дочерних процесса и один pipe.
Перед созданием дочерних процессов bash запускает системный вызов pipe и получает новые файл дескрипторы на временный буфер pipe, но этот буфер никак пока не связывает наши два дочерних процесса.
Для родительского процесса это выглядит так будто pipe уже есть, а дочерних процессов еще нет:
PID command 15771 bash lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21
Затем с помощью системного вызова clone bash создает два дочерних процесса, и наши три процесса будут выглядеть так:
PID command 15771 bash lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21 PID command 9004 bash lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21 PID command 9005 bash lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 3 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 4 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 255 -> /dev/pts/21
Не забываем, что clone клонирует процесс вместе со всеми файл дескрипторами, поэтому в родительском процессе и в дочерних они будут одинаковые. Задача родительского процесса с PID 15771 следить за дочерними процессами, поэтому он просто ждет ответ от дочерних.
Следовательно pipe ему не нужен, и он закрывает файл дескрипторы с номерами 3 и 4.
В первом дочернем процессе bash с PID 9004, системным вызовом dup2, меняет наш STDOUT файл дескриптор с номером 1 на файл дескриптор указывающий на pipe, в нашем случае это номер 3. Таким образом все, что первый дочерний процесс с PID 9004 будет писать в STDOUT, будет автоматически попадать в буфер pipe.
Во втором дочернем процессе с PID 9005 bash меняет с помощью dup2 файл дескриптор STDIN с номером 0. Теперь все, что будет читать наш второй bash с PID 9005, будет читать из pipe.
После этого в дочерних процессах так же закрываются файл дескрипторы с номерами 3 и 4, так как они более не используются.
Файл дескриптор 255 я намеренно игнорирую, он использует для внутренних нужд самого bash и в дочерних процессах будет также закрыт.
Далее в первом дочернем процессе с PID 9004 bash запускает с помощью системного вызова exec исполняемый файл, который мы указали в командной строке, в нашем случае это /usr/bin/cat.
Во втором дочернем процессе с PID 9005 bash запускает второй исполняемый файл, который мы указали, в нашем случае это /usr/bin/sleep.
Системный вызов exec не закрывает файл дескрипторы, если они не были открыты с флагом O_CLOEXEC во время выполнения вызова open. В нашем случае после запуска исполняемых файлов все текущие файл дескрипторы сохранятся.
Проверяем в консоли:
[user@localhost ]$ pgrep -P 15771 9004 9005 [user@localhost ]$ ls -lah /proc/15771/fd/ total 0 dr-x------ 2 user user 0 Oct 7 15:42 . dr-xr-xr-x 9 user user 0 Oct 7 15:42 .. lrwx------ 1 user user 64 Oct 7 15:42 0 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 2 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:42 255 -> /dev/pts/21 [user@localhost ]$ ls -lah /proc/9004/fd total 0 dr-x------ 2 user user 0 Oct 7 15:57 . dr-xr-xr-x 9 user user 0 Oct 7 15:57 .. lrwx------ 1 user user 64 Oct 7 15:57 0 -> /dev/pts/21 l-wx------ 1 user user 64 Oct 7 15:57 1 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 lr-x------ 1 user user 64 Oct 7 15:57 3 -> /dev/zero [user@localhost ]$ ls -lah /proc/9005/fd total 0 dr-x------ 2 user user 0 Oct 7 15:57 .dr-xr-xr-x 9 user user 0 Oct 7 15:57 .. lr-x------ 1 user user 64 Oct 7 15:57 0 -> pipe:[253543032] lrwx------ 1 user user 64 Oct 7 15:57 1 -> /dev/pts/21 lrwx------ 1 user user 64 Oct 7 15:57 2 -> /dev/pts/21 [user@localhost ]$ ps -up 9004 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND user 9004 0.0 0.0 107972 620 pts/21 S+ 15:57 0:00 cat /dev/zero [user@localhost ]$ ps -up 9005 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND user 9005 0.0 0.0 107952 360 pts/21 S+ 15:57 0:00 sleep 10000
Как видите уникальный номер нашего pipe у нас в обоих процессах совпадает. Таким образом у нас есть связь между двумя разными процессами с одним родителем.
Для тех, кто не знаком с системными вызовами, которые использует bash, крайне рекомендую запустить команды через strace и посмотреть, что происходит внутри, например, так:
strace -s 1024 -f bash -c "ls | grep hello"
Вернемся к нашей проблеме с нехваткой места на диске и попыткой сохранить данные без перезапуска процесса. Напишем небольшую программу, которая будет записывать на диск примерно 1 мегабайт в секунду. При этом если по какой-либо причине мы не смогли записать данные на диск, мы будем просто игнорировать это и пытаться записать данные вновь через секунду. В примере я использую Python, вы можете использовать любой другой язык программирования.
[user@localhost ]$ cat openforwrite.py import datetime import time mystr="a"*1024*1024+"\n" with open("123.txt", "w") as f: while True: try: f.write(str(datetime.datetime.now())) f.write(mystr) f.flush() time.sleep(1) except: pass
Запустим программу и посмотрим на файл дескрипторы
[user@localhost ]$ python openforwrite.py & [1] 3762 [user@localhost ]$ ps axuf | grep [o]penforwrite user 3762 0.0 0.0 128600 5744 pts/22 S+ 16:28 0:00 | \_ python openforwrite.py [user@localhost ]$ ls -la /proc/3762/fd total 0 dr-x------ 2 user user 0 Oct 7 16:29 .dr-xr-xr-x 9 user user 0 Oct 7 16:29 .. lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt
Как видим у нас есть наши 3 стандартные файл дескрипторы и еще один, который мы открыли. Проверим размер файла:
[user@localhost ]$ ls -lah 123.txt -rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
данные пишутся, пробуем поменять права на файл:
[user@localhost ]$ sudo chown root: 123.txt [user@localhost ]$ ls -lah 123.txt -rw-rw-r-- 1 root root 168M Oct 7 16:31 123.txt [user@localhost ]$ ls -lah 123.txt -rw-rw-r-- 1 root root 172M Oct 7 16:31 123.txt
Видим, что данные все еще пишутся, хотя наш пользователь не имеет права писать в файл. Попробуем его удалить:
[user@localhost ]$ sudo rm 123.txt [user@localhost ]$ ls 123.txt ls: cannot access 123.txt: No such file or directory
Куда пишутся данные? И пишутся ли вообще? Проверяем:
[user@localhost ]$ ls -la /proc/3762/fd total 0 dr-x------ 2 user user 0 Oct 7 16:29 . dr-xr-xr-x 9 user user 0 Oct 7 16:29 .. lrwx------ 1 user user 64 Oct 7 16:29 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 7 16:29 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 7 16:29 3 -> /home/user/123.txt (deleted)
Да, наш файл дескриптор все еще существует, и мы можем работать с этим файл дескриптором как с нашим старым файлом, мы можем его читать, очищать и копировать.
Смотрим на размер файла:
[user@localhost ]$ lsof | grep 123.txt python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
Размер файла 19923457. Пробуем очистить файл:
[user@localhost ]$ truncate -s 0 /proc/31083/fd/3 [user@localhost ]$ lsof | grep 123.txt python 31083 user 3w REG 8,5 136318390 2621522 /home/user/123.txt
Как видим размер файла только увеличивается и наш транкейт не сработал. Обратимся к документации по системному вызову open. Если при открытии файла мы используем флаг O_APPEND, то при каждой записи операционная система проверяет размер файла и пишет данные в самый конец файла, причем делает это атомарно. Это позволяет нескольким тредам или процессам писать в один и тот же файл. Но в нашем коде мы не используем этот флаг. Мы можем увидеть другой размер файла в lsof после транкейт только если откроем файл для дозаписи, а значит в нашем коде вместо
with open("123.txt", "w") as f:
мы должны поставить
with open("123.txt", "a") as f:
Проверяем с «w» флагом
[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt open("123.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
и с «a» флагом
[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt open("123.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
Программируем уже запущенный процесс
Часто программисты при создании и тестировании программы используют дебагеры (например GDB) или различные уровни логирования в приложении. Linux предоставляет возможность фактически писать и менять уже запущенную программу, например менять значения переменных, устанавливать breakpoint и тд и тп.
Возвращаясь к оригинальному вопросу с нехваткой места на диске для записи файла, попробуем сэмулировать проблему.
Создадим файл для нашего раздела, который мы подмонтируем как отдельный диск:
[user@localhost ~]$ dd if=/dev/zero of=~/tempfile_for_article.dd bs=1M count=10 10+0 records in 10+0 records out 10485760 bytes (10 MB) copied, 0.00525929 s, 2.0 GB/s [user@localhost ~]$
Создадим файловую систему:
[user@localhost ~]$ mkfs.ext4 ~/tempfile_for_article.dd mke2fs 1.42.9 (28-Dec-2013) /home/user/tempfile_for_article.dd is not a block special device. Proceed anyway? (y,n) y ... Writing superblocks and filesystem accounting information: done [user@localhost ~]$
Подмонтируем файловую систему:
[user@localhost ~]$ sudo mount ~/tempfile_for_article.dd /mnt/ [sudo] password for user: [user@localhost ~]$ df -h | grep mnt /dev/loop0 8.7M 172K 7.9M 3% /mnt
Создаем директорию с нашим владельцем:
[user@localhost ~]$ sudo mkdir /mnt/logs [user@localhost ~]$ sudo chown user: /mnt/logs
Откроем файл только на запись в нашей программе:
with open("/mnt/logs/123.txt", "w") as f:
Запускаем
[user@localhost ]$ python openforwrite.py
Ждем несколько секунд
[user@localhost ~]$ df -h | grep mnt /dev/loop0 8.7M 8.0M 0 100% /mnt
Итак, мы получили проблему, описанную в начале этой статьи. Свободного места 0, занятого 100%.
Мы помним, что по условиям задачи мы пытаемся записать очень важные данные, которые нельзя потерять. И при этом нам нужно починить сервис без перезапуска процесса.
Допустим, у нас все же есть место на диске, но в другом разделе, например в /home.
Попробуем «перепрограммировать на лету» наш код.
Смотрим PID нашего процесса, который съел все место на диске:
[user@localhost ~]$ ps axuf | grep [o]penfor user 10078 27.2 0.0 128600 5744 pts/22 R+ 11:06 0:02 | \_ python openforwrite.py
Подключаемся к процессу через gdb
[user@localhost ~]$ gdb -p 10078 ... (gdb)
Смотрим открытые файл дескрипторы:
(gdb) shell ls -lah /proc/10078/fd/ total 0 dr-x------ 2 user user 0 Oct 8 11:06 .dr-xr-xr-x 9 user user 0 Oct 8 11:06 .. lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt
Смотрим информацию о файл дескрипторе с номером 3, который нас интересует
(gdb) shell cat /proc/10078/fdinfo/3 pos: 8189952 flags: 0100001 mnt_id: 482
Помня о том, какой системный вызов делает Python (смотрите выше, где мы запускали strace и находили вызов open), обрабатывая наш код для открытия файла, мы делаем то же самое самостоятельно от имени нашего процесса, но биты O_WRONLY|O_CREAT|O_TRUNC нам нужно заменить на числовое значение. Для этого открываем исходники ядра, например тут и смотрим какие флаги за что отвечают
#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000
Объединяем все значения в одно, получаем 00001101
Запускаем наш вызов из gdb
(gdb) call open("/home/user/123.txt", 00001101,0666) $1 = 4
Итак мы получили новый файл дескриптор с номером 4 и новый открытый файл на другом разделе, проверяем:
(gdb) shell ls -lah /proc/10078/fd/ total 0 dr-x------ 2 user user 0 Oct 8 11:06 . dr-xr-xr-x 9 user user 0 Oct 8 11:06 .. lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:09 3 -> /mnt/logs/123.txt l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt
Мы помним пример с pipe — как bash меняет файл дескрипторы, и уже выучили системный вызов dup2.
Пробуем подменить один файл дескриптор другим
(gdb) call dup2(4,3) $2 = 3
Проверяем:
(gdb) shell ls -lah /proc/10078/fd/ total 0 dr-x------ 2 user user 0 Oct 8 11:06 . dr-xr-xr-x 9 user user 0 Oct 8 11:06 .. lrwx------ 1 user user 64 Oct 8 11:09 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:09 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:06 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:09 3 -> /home/user/123.txt l-wx------ 1 user user 64 Oct 8 11:15 4 -> /home/user/123.txt
Закрываем файл дескриптор 4, так как нам он не нужен:
(gdb) call close (4) $1 = 0
И выходим из gdb
(gdb) quit A debugging session is active. Inferior 1 [process 10078] will be detached. Quit anyway? (y or n) y Detaching from program: /usr/bin/python2.7, process 10078
Проверяем новый файл:
[user@localhost ~]$ ls -lah /home/user/123.txt -rw-rw-r-- 1 user user 5.1M Oct 8 11:18 /home/user/123.txt [user@localhost ~]$ ls -lah /home/user/123.txt -rw-rw-r-- 1 user user 7.1M Oct 8 11:18 /home/user/123.txt
Как видим, данные пишутся в новый файл, проверяем старый:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt -rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Данные не потеряны, приложение работает, логи пишутся в новое место.
Немного усложним задачу
Представим, что данные нам важны, но места на диске у нас нет ни в одном из разделов и подключить диск мы не можем.
Что мы можем сделать, так это перенаправить куда-то наши данные, например в pipe, а данные из pipe в свою очередь перенаправить в сеть через какую-либо программу, например netcat.
Мы можем создать именованный pipe командой mkfifo. Она создаст псевдофайл на файловой системе, даже если на ней нет свободного места.
Перезапускаем приложение, и проверяем:
[user@localhost ]$ python openforwrite.py [user@localhost ~]$ ps axuf | grep [o]pen user 5946 72.9 0.0 128600 5744 pts/22 R+ 11:27 0:20 | \_ python openforwrite.py [user@localhost ~]$ ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 .dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt [user@localhost ~]$ df -h | grep mnt /dev/loop0 8.7M 8.0M 0 100% /mnt
Места на диске нет, но мы успешно создаем там именованный pipe:
[user@localhost ~]$ mkfifo /mnt/logs/megapipe [user@localhost ~]$ ls -lah /mnt/logs/megapipe prw-rw-r-- 1 user user 0 Oct 8 11:28 /mnt/logs/megapipe
Теперь нам надо как-то завернуть все данные, что попадают в этот pipe на другой сервер через сеть, для этого подойдет все тот же netcat.
На сервере remote-server.example.com запускаем
[user@localhost ~]$ nc -l 7777 > 123.txt
На нашем проблемном сервере запускаем в отдельном терминале
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Теперь все данные, которые попадут в pipe автоматически попадут на stdin в netcat, который их отправит в сеть на порт 7777.
Все что нам осталось сделать это начать писать наши данные в этот именованный pipe.
У нас уже есть запущенное приложение:
[user@localhost ~]$ ps axuf | grep [o]pen user 5946 99.8 0.0 128600 5744 pts/22 R+ 11:27 169:27 | \_ python openforwrite.py [user@localhost ~]$ ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt
Из всех флагов нам нужен только O_WRONLY так как файл уже существует и очищать нам его не нужно
[user@localhost ~]$ gdb -p 5946 ... (gdb) call open("/mnt/logs/megapipe", 00000001,0666) $1 = 4 (gdb) shell ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/123.txt l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe (gdb) call dup2(4,3) $2 = 3 (gdb) shell ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 . dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe l-wx------ 1 user user 64 Oct 8 14:20 4 -> /mnt/logs/megapipe (gdb) call close(4) $3 = 0 (gdb) shell ls -lah /proc/5946/fd total 0 dr-x------ 2 user user 0 Oct 8 11:27 .
dr-xr-xr-x 9 user user 0 Oct 8 11:27 .. lrwx------ 1 user user 64 Oct 8 11:28 0 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:28 1 -> /dev/pts/22 lrwx------ 1 user user 64 Oct 8 11:27 2 -> /dev/pts/22 l-wx------ 1 user user 64 Oct 8 11:28 3 -> /mnt/logs/megapipe (gdb) quit A debugging session is active. Inferior 1 [process 5946] will be detached. Quit anyway? (y or n) y Detaching from program: /usr/bin/python2.7, process 5946
Проверяем удаленный сервер remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt -rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Данные идут, проверяем проблемный сервер
[user@localhost ~]$ ls -lah /mnt/logs/ total 7.9M drwxr-xr-x 2 user user 1.0K Oct 8 11:28 . drwxr-xr-x 4 root root 1.0K Oct 8 10:55 .. -rw-rw-r-- 1 user user 7.9M Oct 8 14:17 123.txt prw-rw-r-- 1 user user 0 Oct 8 14:22 megapipe
Данные сохранились, проблема решена.
Пользуясь случаем, передаю привет коллегам из компании Degiro.
Слушайте подкасты Радио-Т.
Всем добра.
В качестве домашнего задания предлагаю подумать, что будет в файл дескрипторах процесса cat и sleep если запустить такую команду:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
Файловые дескрипторы. Операционная система UNIX
Файловые дескрипторы. Операционная система UNIXВикиЧтение
Операционная система UNIX
Робачевский Андрей М.
Содержание
Файловые дескрипторы
Файловый дескриптор представляет собой неотрицательное целое число, возвращаемое системными вызовами, такими как creat(2), open(2) или pipe(2). После получения файлового дескриптора процесс может использовать его для дальнейшей работы с файлом, например с помощью системных вызовов read(2), write(2), close(2) или fcntl(2).
Ядро обеспечивает работу процесса с файлами, используя различные структуры данных, часть из которых расположена в u-area процесса. Напомним, что эта область описывается структурой user. В табл. 4.7 приведены поля структуры user, которые используются ядром для обеспечения доступа процесса к файлу.
Таблица 4.7. Поля структуры user, связанные с файловым дескриптором
Поле Описание u_ofile Указатель на системную файловую таблицу u_pofile Флаги файлового дескриптораФайловый дескриптор связан с этими двумя полями и, таким образом, обеспечивает доступ к соответствующему элементу файловой таблицы (структуре данных file).
В настоящее время в качестве единственного флага файлового дескриптора определен флаг FD_CLOEXEC. Если этот флаг установлен, то производится закрытие файлового дескриптора (аналогично явному вызову close(2)) при выполнении процессом системного вызова exec(2)). При этом для запущенной программы не происходит наследования файлового дескриптора и доступа к файлу.
Более старые версии UNIX используют статическую таблицу дескрипторов, которая целиком хранится в u-area. Номер дескриптора является индексом этой таблицы. Таким образом, размер таблицы, которая обычно содержит 64 элемента, накладывает ограничение на число одновременно открытых процессом файлов. В современных версиях таблица размещается динамически и может увеличиваться при необходимости. Следует, однако, иметь в виду, что и в этом случае максимальное число одновременно открытых файлов регламентируется пределом RLIMIT_NOFILE, который рассматривался в разделе «Ограничения» главы 2. В некоторых версиях, например, Solaris 2.5, данные файловых дескрипторов хранятся не в виде таблицы, а в виде блоков структур uf_entry, поля которой аналогичны приведенным в табл. 4.7.
Содержимое таблицы дескрипторов процесса можно посмотреть с помощью утилиты crash(1M). Команда user покажет содержимое u-area процесса. Например, для текущего командного интерпретатора мы получим следующую информацию:
# crash
> proc #8591
PROC TABLE SIZE = 1498
SLOT ST PID PPID PGID SID UID PRI NAME FLAGS
121 s 8591 8589 8591 8591 286 48 bash load jctl
> user 121
PER PROCESS USER AREA FOR PROCESS 121
PROCESS MISC:
command: bash, psargs: -bash
start: PO Mon 24 18:11:31 1997
mem: 1ebc, type: exec
vnode of current directory: f5b95e40
OPEN FILES, POFILE FLAGS, AND THREAD REFCNT:
[0] : F 0xf62b6030, 0, 0 [1] : F 0xf62b6030, 0, 0
[2] : F 0xf62b6030, 0, 0
cmask: 0022
RESOURCE LIMITS:
cpu time: unlimited/unlimited
file size: unlimited/unlimited
swap size: 2147479552/2147479552
stack size: 8388608/2147479552
coredump size: unlimited/unlimited
file descriptors: 64/1024
address space: unlimited/unlimited
SIGNAL DISPOSITION:
. ..
Данный текст является ознакомительным фрагментом.
4.4.2.1. Отображение переменных FILE* на дескрипторы файлов
4.4.2.1. Отображение переменных FILE* на дескрипторы файлов Стандартные библиотечные функции ввода/вывода и переменные FILE* из <stdio.h>, такие, как stdin, stdout и stderr, построены поверх основанных на дескрипторах файлов системных вызовах.Иногда полезно получить непосредственный
Наследуемые дескрипторы
Наследуемые дескрипторы Часто бывает так, что дочернему процессу требуется доступ к объекту, к которому можно обратиться через дескриптор, определенный в родительском процессе, и если этот дескриптор — наследуемый, то дочерний процесс может получить копию открытого
Абсолютные и самоопределяющиеся относительные дескрипторы безопасности
Абсолютные и самоопределяющиеся относительные дескрипторы безопасности
Программа 15. 5, позволяющая изменять ACL, удобна тем, что просто заменяет один дескриптор безопасности (SD) другим. В то же время, при замене существующих SD следует проявлять осторожность, поскольку они
11.2.1. Файловые дескрипторы
11.2.1. Файловые дескрипторы Когда процесс получает доступ к файлу (что обычно называют открытием файла), то ядро возвращает ему файловый дескриптор, который затем используется процессом для всех операций с файлом. Файловые дескрипторы — это маленькие положительные целые
Индексные дескрипторы
Индексные дескрипторы Индексный дескриптор, или inode, содержит информацию о файле, необходимую для обработки данных, т.е. метаданные файла. Каждый файл ассоциирован с одним inode, хотя может иметь несколько имен в файловой системе, каждое из которых указывает на один и тот же
Виртуальные индексные дескрипторы
Виртуальные индексные дескрипторы
Дисковый файл обычно имеет связанную с структуру данных, называемую метаданными или inode, где хранятся основные характеристики данного файла и с помощью которой обеспечивается доступ к его данным. Одним из исключений из этого правила
2.5 Индексные дескрипторы
2.5 Индексные дескрипторы Файл имеет несколько атрибутов: имя, содержимое и служебную информацию (права доступа и даты модификации). Служебная информация размещается в индексном дескрипторе вместе с важной системной информацией, такой, как размер файла, место хранения
16.3. Индексные дескрипторы файлов
16.3. Индексные дескрипторы файлов Каждому файлу на диске соответствует один и только один индексный дескриптор файла, который идентифицируется своим порядковым номером — индексом файла. Это означает, что число файлов, которые могут быть созданы в файловой системе,
Файловые таблицы
Файловые таблицы
Эта группа таблиц содержит информацию обо всех файлах, составляющих программный продукт. Большая часть этих файлов перечислена в таблице File. Таблица Directory не входит в эту группу, но, тем не менее, очень тесно связана с ней, так как отражает структуру
1.1.3. Дескрипторы вместо классов
1.1.3. Дескрипторы вместо классов Программируя в Delphi, мы быстро привыкаем к тому, что каждый объект реализуется экземпляром соответствующего класса. Например, кнопка реализуется экземпляром класса TButton, контекст устройства — классом TCanvas. Но когда создавались первые
Файловые менеджеры
Файловые менеджеры На протяжении всей книги уже не раз упоминалось о двух популярных файловых менеджерах – Konqueror из KDE и Nautilus из GNOME. Пользователям, работающим в консоли, можно предложить Midnight Commander (пакет mc). Две панели сине-белого цвета со строкой меню, расположенной
7.
![](/800/600/http/ppt4web.ru/images/242/13045/640/img14.jpg)
7.2.5. Дескрипторы файлов процесса Элемент fd файловой системы /proc — это подкаталог, в котором содержатся записи обо всех файлах, открытых процессом. Каждая запись представляет собой символическую ссылку на файл или устройство. Через эти ссылки можно осуществлять чтение и
6.5. Файловые структуры
6.5. Файловые структуры Файловая структура может быть одно– или многоуровневой. В одноуровневой структуре на носителе информации имена файлов образуют линейную последовательность, в многоуровневой, или иерархической, – древовидную структуру. Примером такой структуры
6.6. Файловые системы
6.6. Файловые системы 6.6.1. Назначение и функционирование файловой системы В операционных системах файловая система относится к основным понятиям и определяется как общая система, которая устанавливает правила присвоения имен файлам, хранение, организацию и обработку
Дескриптор файла — frwiki.
![](/800/600/http/image3.slideserve.com/5589936/slide28-l.jpg)
Дескрипторы файлов для ввода, вывода и ошибок
В вычислениях , дескриптор файла является абстрактным ключом для доступа к файлу (это целое число).
Этот термин обычно используется для операционных систем POSIX .
В терминологии Microsoft Windows и в контексте библиотеки stdio.h предпочтительным является термин дескриптор файла , хотя технически это другой объект ( см. Ниже ).
Резюме
- 1 Объяснение
- 2 файловая ручка
- 3 Операции с файловыми дескрипторами
- 4 Файловые дескрипторы и емкость
- 5 См. Также
Пояснения
В POSIX дескриптор файла — это целое число , а в языке C — целое число типа int .
Есть три стандартных файловых дескриптора POSIX для любого процесса, не являющегося демоном :
Целое число | Фамилия | Константа (unistd.h) | Поток |
---|---|---|---|
0 | Стандартный вход | STDIN_FILENO | стандартный ввод |
1 | Стандартный вывод | STDOUT_FILENO | стандартный вывод |
2 | Стандартная ошибка | STDERR_FILENO | stderr |
Обычно дескриптор файла — это индекс записи в резидентном ядре , структура данных, содержащая сведения обо всех открытых файлах.
В POSIX эта структура данных называется таблицей файловых дескрипторов. И у каждого процесса есть своя таблица дескрипторов файлов. Пользовательское приложение передает абстрактный ключ ядру с помощью системного вызова, и ядро будет обращаться к файлу, используя этот ключ. Приложение не может напрямую читать или записывать таблицу файловых дескрипторов.
В системе Unix файловые дескрипторы могут относиться к файлам, каталогам , блочным или символьным устройствам (часто называемым специальными файлами), именованным каналам или анонимным каналам.
файл-дескрипторФайловый дескриптор FILE * стандартной библиотеки ввода / вывода C технически является указателем на структуру данных, управляемую подпрограммами этой библиотеки. В системах Unix одна из этих структур включает файловый дескриптор для рассматриваемого объекта. Поскольку имя дескриптора файла относится к этому дополнительному уровню, оно не взаимозаменяемо с именем дескриптора файла .
Чтобы еще больше усложнить терминологию, Microsoft Windows также использует термин дескриптор файла для обозначения низкоуровневой конструкции, то есть дескрипторов файлов POSIX. Библиотеки Microsoft C также предоставляют функции совместимости, которые «обертывают» эти собственные дескрипторы для поддержки «POSIX-подобных» соглашений о дескрипторах файлов, как описано выше.
Операции с файловыми дескрипторами
Современный Unix обычно предоставляет следующие операции с файловыми дескрипторами.
- Системные вызовы для создания файловых дескрипторов
- open (), open64 (), creat (), creat64 ()
- сокет ()
- socketpair ()
- труба ()
- Операции с одним файловым дескриптором
- читай пиши ()
- recv (), отправить ()
- recvmsg (), sendmsg () (позволяет отправлять дескрипторы файлов другому процессу)
- послать файл ()
- lseek (), lseek64 ()
- fstat (), fstat64 ()
- fchmod ()
- fchown ()
- Операции с несколькими файловыми дескрипторами
- select (), pselect ()
- голосование ()
- Операции с таблицей дескрипторов файлов
- закрыть (дескриптор)
- dup (дескриптор)
- dup2 ()
- fcntl (F_DUPFD)
- fcntl (F_GETFD и F_SETFD)
- Операции, изменяющие состояние процесса
- fchdir (): изменить текущий рабочий каталог вызывающего процесса, предоставленный как файловый дескриптор
- mmap (): проецирует части файла в адресное пространство процесса
- Блокировка файла
- стадо ()
- fcntl (F_GETLK, F_SETLK и F_SETLKW)
- lockf ()
- Розетки
- соединять ()
- связывать ()
- Слушать ()
- accept (): создать новый дескриптор файла во время входящего соединения
- getsockname ()
- getpeername ()
- getsockopt (), setsockopt ()
- shutdown (): закрыть один или оба конца полнодуплексного соединения
- Разные
- ioctl (): большой набор различных операций с одним файловым дескриптором, часто связанный с устройством.
Дескрипторы файлов и емкость
Дескрипторы файлов Unix — это возможности . Их можно передавать между процессами в сокетах в домене UNIX с помощью системного вызова sendmsg ().
Примером C-списка является таблица дескрипторов файлов Unix .
Смотрите также
<img src=»//fr.wikipedia.org/wiki/Special:CentralAutoLogin/start?type=1×1″ alt=»» title=»»>
Потоки и файловый дескриптор в C/C++ : Программирование
Сообщения без ответов | Активные темы | Избранное
beardy |
| ||
14/05/15 |
| ||
| |||
Xaositect |
| |||
06/10/08 |
| |||
| ||||
beardy |
| ||
14/05/15 |
| ||
| |||
iifat |
| |||
16/02/13 |
| |||
| ||||
Показать сообщения за: Все сообщения1 день7 дней2 недели1 месяц3 месяца6 месяцев1 год Поле сортировки АвторВремя размещенияЗаголовокпо возрастаниюпо убыванию |
Страница 1 из 1 | [ Сообщений: 4 ] |
Модераторы: Toucan, PAV, Karan, maxal, Супермодераторы
Кто сейчас на конференции |
Сейчас этот форум просматривают: нет зарегистрированных пользователей |
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения |
Найти: |
Файловые дескрипторы в дочернем процессе
Содержание:
- 1 Решение
- 1.
1 Персональные инструменты
- 1.
- 2 Содержание
- 3 Таблицы дескрипторов файлов и системные таблицы открытых файлов
- 3.1 Таблица дескрипторов файлов
- 3.2 Таблица открытых файлов
- 4 Управление дескрипторами файлов
- 5 Совместная работа с открытыми файлами
- 6 Копирование дескрипторов файлов
- 6.0.1 Функции dup и dup2
- 6.0.2 Функция fork
- 6.0.3 Функция fcntl
- 7 Стандартные дескрипторы файлов
- 8 Ограничение на число дескрипторов файлов
Я публикую свой код просто для контекста моего вопроса. Я явно не ищу, чтобы вы помогли это исправить, я скорее хочу понять системный вызов dup2, который я просто не отвечаю на странице руководства и во множестве других вопросов stackoverflow.
Для контекста этот код представляет собой шаг выполнения базовой оболочки Linux. Объект команды содержит аргументы команд, «имя» ввода-вывода и дескрипторы ввода-вывода (думаю, я мог бы избавиться от дескрипторов файлов в виде полей).
Что мне труднее всего понять, так это когда и какие файловые дескрипторы закрывать. Думаю, я просто задам несколько вопросов, чтобы попытаться улучшить мое понимание концепции.
1) С моим массивом файловых дескрипторов, используемых для обработки каналов, у родителя есть копия всех этих дескрипторов. Когда дескрипторы, удерживаемые родителем, закрыты? И даже более того, какие дескрипторы? Это все из них? Все из них остались неиспользованными исполняемыми командами?
2) Какие процессы при обработке каналов внутри дочерних процессов остаются открытыми? Скажите, если я выполню команду: ls -l | Grep
«[username]», какие дескрипторы следует оставить открытыми для процесса ls? Просто конец записи трубы? И если да, то когда? Тот же вопрос относится к команде grep.
3) Когда я обрабатываю перенаправление ввода-вывода в файл, новый файл должен быть открыт и дублирован на STDOUT (я не поддерживаю перенаправление ввода). Когда этот дескриптор закрывается? Я видел в примерах, что он закрывается сразу после вызова dup2, но как тогда что-то записывается в файл, если файл был закрыт?
Спасибо заранее Я застрял на этой проблеме в течение нескольких дней, и я действительно хотел бы закончить с этим проектом.
РЕДАКТИРОВАТЬ Я обновил его с помощью измененного кода и примера вывода для всех, кто заинтересован в предложении конкретной помощи по моей проблеме. Сначала у меня есть весь цикл for, который обрабатывает выполнение. Это было обновлено с моими вызовами, чтобы закрыть на различных файловых дескрипторах.
При выполнении этого кода я получаю следующий вывод
Выход из ls -l > output.txt подразумевает, что я закрываю неправильный дескриптор, но закрытие другого связанного дескриптора, не отображая ошибки, не обеспечивает вывод в файл. Как продемонстрировано ls -l , grep «cook» , должен генерировать вывод на консоль.
Решение
С моим массивом файловых дескрипторов, используемых для обработки каналов, родительский
имеет копию всех этих дескрипторов. Когда дескрипторы хранятся
родитель закрыт? И даже более того, какие дескрипторы? Это все из
их? Все из них остались неиспользованными исполняемыми командами?
Дескриптор файла может быть закрыт одним из 3 способов:
- Вы явно звоните close() в теме.
- Процесс завершается, и операционная система автоматически закрывает каждый дескриптор файла, который все еще был открыт.
- Когда процесс вызывает один из семи exec() функции и файловый дескриптор имеет O_CLOEXEC флаг.
Как видите, в большинстве случаев файловые дескрипторы остаются открытыми, пока вы не закроете их вручную. Это то, что происходит в вашем коде тоже — так как вы не указали O_CLOEXEC дескрипторы файлов не закрываются при вызове дочернего процесса execvp() , У ребенка они закрываются после того, как ребенок заканчивается. То же самое касается родителей. Если вы хотите, чтобы это произошло в любое время до завершения, вы должны вручную вызвать close() ,
При обработке каналов внутри дочерних элементов, дескрипторы которых остаются
открыть какими процессами? Скажите, если я выполню команду: ls -l | Grep
«[username]», какие дескрипторы должны быть оставлены открытыми для ls
процесс? Просто конец записи трубы? И если да, то когда? Такой же
вопрос относится к команде grep.
Вот (грубое) представление о том, что делает оболочка при вводе ls -l | grep «username» :
- Оболочка вызывает pipe() создать новую трубу. Дескрипторы файла канала наследуются потомками на следующем шаге.
- Оболочка дважды разветвляется, давайте назовем эти процессы c1 а также c2 , Давайте предположим c1 побежит ls а также c2 побежит grep ,
- В c1 канал чтения канала закрыт close() , а затем он вызывает dup2() с каналом записи трубы и STDOUT_FILENO чтобы написать stdout эквивалентно записи в трубу. Затем один из семи exec() функции вызывается, чтобы начать выполнение ls , ls пишет stdout , но так как мы продублировали stdout на канал записи канала, ls буду писать в трубу.
- В c2 , происходит обратное: канал записи канала закрыт, а затем dup2() призван сделать stdin указать канал чтения канала. Затем один из семи exec() функции вызывается, чтобы начать выполнение grep , grep читает из stdin , но так как мы dup2() стандартный ввод в канал чтения канала, grep буду читать из трубы.
Когда я обрабатываю перенаправление ввода-вывода в файл, новый файл должен быть открыт
и дублируется на STDOUT (я не поддерживаю перенаправление ввода). Когда делает
этот дескриптор закрыли? Я видел в примерах, что это закрывается
сразу после звонка на dup2, но как потом что нибудь получится
записано в файл, если файл был закрыт?
Итак, когда вы звоните dup2(a, b) Либо одно из них верно:
- a == b , В этом случае ничего не происходит и dup2() возвращается преждевременно. Нет файловых дескрипторов закрыты.
- a != b , В этом случае, b закрывается при необходимости, а затем b сделано для ссылки на ту же запись таблицы файлов, что и a , Запись таблицы файлов представляет собой структуру, которая содержит текущее смещение файла и флаги состояния файла; несколько файловых дескрипторов могут указывать на одну и ту же запись таблицы файлов, и это именно то, что происходит, когда вы дублируете файловый дескриптор. Так, dup2(a, b) имеет эффект создания a а также b поделиться одной и той же записи таблицы файлов.
Как следствие, писать a или же b в конечном итоге запись в тот же файл. Таким образом, файл, который закрыт b не a , если ты dup2(a, STDOUT_FILENO) ты закрываешь stdout и вы делаете stdout дескриптор файла указывает на ту же запись таблицы файлов, что и a , Любая программа, которая пишет в stdout будет вместо этого писать в файл, так как stdout Описатель файла указывает на файл, который вы скопировали.
ОБНОВИТЬ:
Итак, для вашей конкретной проблемы, вот что я должен сказать после краткого просмотра кода:
Вы не должны звонить close(STDOUT_FILENO) здесь:
Если вы закроете stdout , вы получите ошибку в будущем, когда вы попытаетесь написать stdout , Вот почему вы получаете ls: write error: Bad file descriptor , В конце концов, ls пишет stdout , но вы закрыли это. К сожалению!
Вы делаете это задом наперед: вы хотите закрыть outfd вместо. Вы открыли outfd чтобы вы могли перенаправить STDOUT_FILENO в outfd , как только перенаправление сделано, вам не нужно outfd больше, и вы можете закрыть его. Но вы определенно не хотите закрывать stdout потому что идея состоит в том, чтобы иметь stdout записать в файл, на который ссылалась outfd ,
Итак, продолжайте и сделайте это:
Обратите внимание на финал if необходимо: если outfd случайно оказывается равным STDOUT_FILENO Вы не хотите закрывать его по причинам, которые я только что упомянул.
То же самое относится и к коду внутри else if (command->getOutputFD() == REDIRECTAPPEND) : хочешь закрыть outfd скорее, чем STDOUT_FILENO :
Это должно, по крайней мере, заставить вас ls -l работать как положено.
Что касается проблемы с трубами: ваше управление трубами на самом деле не правильно. Из кода, который вы показали, где и как не понятно pipefd и сколько каналов вы создаете, но обратите внимание, что:
- Процесс никогда не сможет читать из канала и записывать в другой канал. Например, если outfile не является STDOUT а также infile не является STDIN в итоге вы закрываете каналы чтения и записи (и, что еще хуже, после закрытия канала чтения вы пытаетесь продублировать его).
Это никак не сработает.
- Родительский процесс закрывает каждый канал перед ожиданием завершения дочерних процессов. Это провоцирует состояние гонки.
fork() — системный вызов в Unix-подобных операционных системах, создающий новый процесс (потомок), который является практически полной копией процесса-родителя, выполняющего этот вызов.
Концепция ветвления процессов впервые описана в 1962 году Мелвином Конвеем [en] и в 1964 году реализована в форме системного вызова в Project Genie [en] , откуда заимствована Томпсоном при реализации Unix; позднее вызов включён в стандарт POSIX.
Между процессом-потомком, порождаемым вызовом fork() , и процессом-родителем существуют различия:
- PID процесса-потомка отличен от PID процесса-родителя;
- значению PPID процесса-потомка присваивается значение PID процесса-родителя;
- процесс-потомок получает собственную таблицу файловых дескрипторов, являющуюся копией таблицы процесса-родителя на момент вызова fork() ; это означает, что открытые файлы наследуются, но если процесс-потомок, например, закроет какой-либо файл, то это не повлияет на таблицу дескрипторов процесса-родителя;
- для процесса-потомка очищаются все ожидающие доставки сигналы;
- временная статистика выполнения процесса-потомка в таблицах ОС обнуляется;
- блокировки памяти и записи, установленные в процессе-родителе, не наследуются.
После вызова fork() алгоритм обычно разветвляется (в случае успешного выполнения функции fork() , она возвращает PID процесса-потомка родительскому процессу и нуль — процессу-потомку. Если порождение процесса-потомка закончилось неудачей, функция fork() возвращает значение −1).
После fork() процесс-потомок чаще всего выполняет системный вызов exec() , загружающий в пространство процесса новую программу (именно так, и только так, в Unix-системе выполняется запуск программы в отдельном процессе). Так, первый (нулевой) процесс Unix (ядро системы) создаёт свою копию, чтобы запустить init (процесс с P >
Некоторые программы создают дочерние процессы не для запуска другой программы, а для выполнения параллельной задачи. Так, например, поступают простые сетевые серверы — при подсоединении клиента, сервер создаёт свою копию (дочерний процесс), которая обслуживает клиентское соединение и завершается по его закрытии. Родительский же процесс продолжает ожидать новых соединений.
Вызов fork() выполняется довольно долго, так как требует копирования большого количества данных. Для того чтобы это обойти, некоторые сетевые серверы (например, веб-серверы Apache и Lighttpd), создают дочерние процессы заранее, чтобы уменьшить время отклика сервера. Также существуют «облегчённые» реализации fork() (например, в ядре Linux [1] ), отображающие в новый процесс страницы памяти родительского, вместо того чтобы их копировать (новая страница создаётся только при изменении её содержимого одним из процессов), что существенно снижает время создания нового процесса (техника copy-on-write).
Персональные инструменты
Дескриптор файла — это целое число без знака, с помощью которого процесс обращается к открытому файлу. Количество дескрипторов файлов, доступных процессу, ограничено параметром /OPEN_MAX, заданным в файле sys/limits.h. Кроме того, количество дескрипторов файлов можно задать с помощью флага -n команды ulimit . Дескрипторы файлов создаются при выполнении функций open , pipe , creat и fcntl . Обычно каждый процесс работает с уникальным набором дескрипторов. Однако эти же дескрипторы могут применяться и дочерними процессами, созданными с помощью функции fork. Кроме того, дескрипторы можно скопировать с помощью функций fontal , dup и dup2 .
Все открытые файлы ссылаются к ядру через так называемые файловые дескрипторы. Файловый дескриптор — это неотрицательное целое число. Когда мы открываем существующий файл и создаем новый файл, ядро возвращает процессу файловый дескриптор.
Содержание
По умолчанию UNIX-шеллы связывают файловый дескриптор 0 со стандартным вводом процесса (терминал), файловый дескриптор 1 — со стандартным выводом (терминал), и файловый дескриптор 2 — со стандартной ошибкой (то есть то куда выводятся сообщения об ошибках). Это соглашение соблюдается многими UNIX-шеллами и многими приложениями — и в ни коем случае не является составной частью ядра.
Стандарт POSIX.1 заменил «магические числа» 0,1,2 символическими константами STDIN_FILENO, STDOUT_FILENO и STDERR_FILENO соответственно.
Файловые дескрипторы могут принимать значения от 0 до OPEN_MAX. Старые версии UNIX имели верхний предел до 19, позволяя одному процессу открывать до 20 файлов. Сейчас это значение увеличено до нескольких тысяч.
Дескрипторы файлов выполняют роль индексов таблицы дескрипторов, которая расположена в области u_block и создается ядром для каждого процесса. Чаще всего процесс получает дескрипторы с помощью операций open и creat , а также путем наследования от родительского процесса. При выполнении операции fork таблица дескрипторов копируется для дочернего процесса. В результате дочерний процесс получает право обращаться к файлам родительского процесса.
Таблицы дескрипторов файлов и системные таблицы открытых файлов
Структуры данных, содержащие список открытых файлов и список дескрипторов файлов, позволяют отслеживать обращения процессов к файлам и гарантировать целостность данных.
Таблица дескрипторов файлов
Преобразует индексы таблицы (дескрипторы файлов) в указатели на открытые файлы. Для каждого процесса в области u_block создается своя собственная таблица дескрипторов. Каждая запись такой таблицы содержит следующие поля: поле флагов и указатель на файл. Допустимо не более OPEN_MAX дескрипторов файлов. Таблица дескрипторов файлов имеет следующую структуру:
Таблица открытых файлов
Содержит записи с информацией обо всех открытых файлах. В записи этой таблицы хранится текущее смещение указателя в файле, которое используется во всех операциях чтения и записи в файл, а также режим открытия файла (O_RDONLY, O_WRONLY или O_RDWR). В структуре таблицы открытых файлов хранится смещение указателя в файле. При выполнении операции чтения-записи система выполняет неявный сдвиг указателя. Например, при чтении или записи x байт указатель также будет перемещен на x байт. Для изменения положения указателя в файлах с прямым доступом применяется функция seek . Для потоковых файлов (например, каналов и сокетов) понятие смещения не поддерживается, так как произвольный доступ к этим файлам невозможен.
Управление дескрипторами файлов
Поскольку с файлами может работать несколько пользователей, необходимо, чтобы связанные процессы работали с общим указателем смещения, а независимые процессы — с собственным указателем смещения в файле. В записи таблицы открытых файлов содержится счетчик обращений к файлу, отражающий число дескрипторов, соответствующих данному файлу.
Несколько обращений к файлу может потребоваться в следующих случаях:
- Файл открыт еще одним процессом
- Дочерний процесс унаследовал дескрипторы файлов, открытых родительским процессом
- Дескриптор файла скопирован с помощью функции fcntl или dup
Совместная работа с открытыми файлами
При выполнении каждой операции открытия в таблицу открытых файлов добавляется запись. Это гарантирует, что каждый процесс будет работать со своим указателем в файле. Такой подход позволяет сохранить целостность данных.
При копировании дескриптора два процесса начинают работать с одним и тем же указателем. В этом случае оба процесса могут попытаться одновременно обратиться к файлу, при этом данные будут считаны или записаны не последовательно.
Копирование дескрипторов файлов
Существуют следующие способы копирования дескрипторов файлов: функция dup или dup2 , функция fork и функция fcntl .
Функции dup и dup2
Функция fork
Функция fcntl
Стандартные дескрипторы файлов
При запуске программы в оболочке открывается три дескриптора 0, 1 и 2. По умолчанию с ними связаны следующие файлы:
Стандартный ввод. | |
1 | Стандартный вывод. |
2 | Стандартный вывод сообщений об ошибках. |
Перечисленные дескрипторы файлов связаны с терминалом. Это означает, что при чтении данных из файла с дескриптором 0 программа получает ввод с терминала, а при записи данных в файлы с дескрипторами 1 и 2 они выводятся на терминал. При открытии других файлов дескрипторы присваиваются в порядке возрастания.
Если ввод-вывод перенаправляется с помощью операторов (знак больше), то стандартные дескрипторы связываются с другими файлами. Например, следующая команда связывает дескрипторы файлов 0 и 1 с необходимыми файлами (по умолчанию эти дескрипторы связаны с терминалом).
В данном примере дескриптор 0 будет связан с файлом FileX, а дескриптор 1 — с файлом FileY. Дескриптор 2 не будет изменен. Программе достаточно знать, что дескриптор 0 представляет файл ввода, а дескрипторы 1 и 2 — файлы вывода. Информация о том, с какими конкретно файлами связаны эти дескрипторы, ей не нужна.
В следующем примере программы продемонстрировано перенаправление стандартного вывода:
При получении запроса на дескриптор выделяется первый свободный дескриптор из таблицы дескрипторов (дескриптор с наименьшим номером). Однако с помощью функции dup файлу можно присвоить любой дескриптор.
Ограничение на число дескрипторов файлов
Максимальное число дескрипторов, которое может использоваться в одном процессе, ограничено. Значение по умолчанию указывается в файле /etc/security/limits и обычно равно 2000. Для изменения ограничения можно воспользоваться командой ulimit или функцией setrlimit . Максимальное число определяется константой OPEN_MAX.
ДЕСКРИПТОР — Что такое ДЕСКРИПТОР?
Слово состоит из 10 букв: первая д, вторая е, третья с, четвёртая к, пятая р, шестая и, седьмая п, восьмая т, девятая о, последняя р,
Слово дескриптор английскими буквами(транслитом) — deskriptor
- Буква д встречается 1 раз. Слова с 1 буквой д
- Буква е встречается 1 раз. Слова с 1 буквой е
- Буква с встречается 1 раз. Слова с 1 буквой с
- Буква к встречается 1 раз. Слова с 1 буквой к
- Буква р встречается 2 раза.
Слова с 2 буквами р
- Буква и встречается 1 раз. Слова с 1 буквой и
- Буква п встречается 1 раз. Слова с 1 буквой п
- Буква т встречается 1 раз. Слова с 1 буквой т
- Буква о встречается 1 раз. Слова с 1 буквой о
Дескриптор
Дескриптор — лексическая единица: — выраженная информативным словом (вербально) или кодом; и — являющаяся именем класса синонимичных или близких по смыслу ключевых слов.
glossary.ru
ДЕСКРИПТОР [descriptor] — единица языка информационно-поисковой системы, соответствующая определенному ключевому или базовому понятию, включенному в тезаурус этой системы.
Лопатников. — 2003
Дескриптор — лексическая единица: — выраженная информативным словом (вербально) или кодом; и — являющаяся именем класса синонимичных или близких по смыслу ключевых слов.
Словарь финансовых терминов
ДЕСКРИПТОР слово, словосочетание или целое высказывание, которые отражают содержание перелагаемого текста в наиболее сжатом виде. В зависимости от характера передаваемого содержания Д. делятся на номинативные Д.
Педагогическое речеведение. — 1998
Дескриптор шлюза
Дескриптор шлюза — служебная структура данных, служащая для различных переходов. Используется только в защищённом режиме. В реальном режиме некоторым аналогом может служить дальний адрес. Длина дескриптора стандартна и равна восьми байтам.
ru.wikipedia.org
Дескриптор сегмента
Дескриптор сегмента (в архитектуре x86) — служебная структура в памяти, которая определяет сегмент. Длина дескриптора равна 8 байт .
ru.wikipedia.orgБаза (жёлтые поля, 32 бита) — начало сегмента в линейной памяти Лимит (красные поля, 20 бит)…
Код дескриптора
Код дескриптора — код, используемый в информационно-поисковом тезаурусе для представления эквивалентных дескрипторов и их синонимов. По-английски: Concept symbol См. также: Информационно-поисковые тезаурусы
Словарь финансовых терминов
Код дескриптора — код, используемый в информационно-поисковом тезаурусе для представления эквивалентных дескрипторов и их синонимов.
glossary.ru
Файловый дескриптор
Ко всем потокам ввода-вывода (которые могут быть связаны как с файлами, так и с папками, сокетами и FIFO) можно получить доступ через так называемые файловые дескрипторы.
ru.wikipedia.orgФайловый дескриптор — это неотрицательное целое число.
Нижестоящий дескриптор
Нижестоящий дескриптор — дескриптор, обозначающий либо видовое понятие, либо часть по отношению к понятию, представленному вышестоящим дескриптором. По-английски: Narrower term Синонимы: Узкий дескриптор См. также: Лексико-семантические указатели
Словарь финансовых терминов
Нижестоящий дескриптор — дескриптор, обозначающий либо видовое понятие, либо часть по отношению к понятию, представленному вышестоящим дескриптором.
glossary.ru
Партитивный дескриптор
Партитивный дескриптор — нижестоящий дескриптор, представляющий часть или элемент в отношении часть-целое.
glossary.ru
Партитивный дескриптор — нижестоящий дескриптор, представляющий часть или элемент в отношении часть-целое. По-английски: Partitive term См. также: Лексико-семантические указатели
Словарь финансовых терминов
Технические дескрипторы
Технические дескрипторы — переменные, используемые для описания условий финансового рынка на основе технического анализа: цены, объем торговли, число открытых позиций (для фьючерсных и опционных рынков).
Словарь финансовых терминов
Технические дескрипторы — переменные, используемые для описания условий финансового рынка на основе технического анализа: цены, объем торговли, число открытых позиций (для фьючерсных и опционных рынков).
glossary.ru
Технические дескрипторы Переменные, используемые для описания условий финансового рынка на основе технического анализа.
Инвестиционный словарь
Ассоциативный дескриптор
Ассоциативный дескриптор — дескриптор, связанный с другим дескриптором семантической связью, характер которой не указывается.
glossary.ru
Ассоциативный дескриптор — дескриптор, связанный с другим дескриптором семантической связью, характер которой не указывается. По-английски: Related term См. также: Лексико-семантические указатели
Словарь финансовых терминов
Русский язык
Дескри́птор, -а.
Орфографический словарь. — 2004
- Слова из слова «дескриптор»
- Слова на букву «д»
- Слова, начинающиеся на «де»
- Слова c буквой «р» на конце
- Слова c «ор» на конце
- Слова, начинающиеся на «дес»
- Слова, начинающиеся на «деск»
- Слова, оканчивающиеся на «тор»
- Слова, заканчивающиеся на «птор»
- десквамация
- дескриптивист
- дескриптивный
- дескриптор
- дескрипция
- десмолаза
- десмолиз
Документация JDK 19 — Главная
Обзор
- Прочтите меня
- Примечания к выпуску
- Что нового
- Руководство по миграции
- Загрузить JDK
- Руководство по установке
- Формат строки версии
Инструменты
- Технические характеристики инструментов JDK
- Руководство пользователя JShell
- Руководство по JavaDoc
- Руководство пользователя средства упаковки
Язык и библиотеки
- Обновления языка
- Основные библиотеки
- HTTP-клиент JDK
- Учебники по Java
- Модульный JDK
- Руководство программиста API бортового регистратора
- Руководство по интернационализации
Технические характеристики
- Документация API
- Язык и ВМ
- Имена стандартных алгоритмов безопасности Java
- банок
- Собственный интерфейс Java (JNI)
- Инструментальный интерфейс JVM (JVM TI)
- Сериализация
- Проводной протокол отладки Java (JDWP)
- Спецификация комментариев к документации для стандартного доклета
- Прочие характеристики
Безопасность
- Руководство по безопасному кодированию
- Руководство по безопасности
Виртуальная машина HotSpot
- Руководство по виртуальной машине Java
- Настройка сборки мусора
Управление и устранение неполадок
- Руководство по устранению неполадок
- Руководство по мониторингу и управлению
- Руководство по JMX
Client Technologies
- Руководство по специальным возможностям Java
3 файловых дескриптора
Одна из первых вещей, которую узнает программист UNIX, это то, что каждая работающая программа начинается уже с трех файлов открыт:
Таблица 3. 1 Стандартные файлы, предоставляемые Unix
Описательное имя | Краткое имя | Номер файла | Description |
---|---|---|---|
Standard In | stdin | 0 | Input from the keyboard |
Standard Out | stdout | 1 | Output to the console |
Standard Error | stderr | 2 | Вывод ошибки на консоль |
файл представляет. Значение, возвращаемое открытый вызов
называется файловый дескриптор и по сути является индексом
в массив открытых файлов, хранящихся в ядре.
Рисунок 3.2 Абстракция
Короче говоря, файловый дескриптор — это ворота в абстракции ядра от базового оборудования. Общий вид абстракция для физических устройств показана на рисунке 3.2, Абстракция.
Начиная с самого низкого уровня, операционной системе требуется
программист для создания драйвер устройства будет
может обмениваться данными с аппаратным устройством. Этот драйвер устройства
написанный для API, предоставляемого ядром, как в примере 2.1.2, Абстракция в
include/linux/virtio.h
; драйвер устройства предоставит
набор функций, которые ядро вызывает в ответ на
различные требования. В приведенном выше упрощенном примере мы можем видеть
драйверы обеспечивают чтение
и напишите
функцию которая будет
вызывается в ответ на аналогичные операции над
дескриптор файла. Драйвер устройства знает, как преобразовать эти
общие запросы в конкретные запросы или команды для
конкретное устройство.
Чтобы обеспечить абстракцию пространства пользователя, ядро
обеспечивает файловый интерфейс через то, что обычно называется уровень устройства . Физические устройства на хосте
представлены файлом в специальной файловой системе, такой как /dev
. В UNIX-подобных системах
так называемые устройства-узлы имеют то, что называется основной и дополнительный числа, которые позволяют ядру ассоциировать определенные узлы с
их основной драйвер. Их можно определить с помощью
ls
, как показано в Примере 3.1, Пример старшего и младшего номеров.
$ ls -l /dev/null /dev/zero /dev/tty crw-rw-rw- 1 root root 1, 3 26 августа 13:12 /dev/null crw-rw-rw- 1 root root 5, 0 2 сент. 15:06 /dev/tty crw-rw-rw- 1 root root 1, 5 26 августа 13:12 /dev/zero
Пример 3.1 Пример старшего и младшего номеров
Это приводит нас к дескриптору файла, который является дескриптором
пользовательское пространство использует для общения с базовым устройством. Заграницей
смысл, что происходит, когда файл open
ed заключается в том, что ядро
используя информацию о пути для сопоставления файлового дескриптора с
то, что обеспечивает соответствующее читать
и пишем
и т.д., API. Когда это открыть
для устройства
( /dev/sr0
выше), майор и
младший номер открытого узла устройства предоставляет информацию
ядро должно найти правильный драйвер устройства и завершить
отображение. После этого ядро будет знать, как маршрутизировать дальнейшие вызовы.
например
прочитать
в базовый
функции, предоставляемые драйвером устройства.
Файл, не являющийся устройством, работает аналогично, хотя есть больше слоев между ними. Абстракция здесь точка монтирования ; монтирование файловой системы имеет двойная цель настройки сопоставления, чтобы файловая система знала базовое устройство, которое обеспечивает хранилище, и ядро знает что файлы, открытые под этой точкой монтирования, должны быть направлены на драйвер файловой системы. Как и драйверы устройств, файловые системы записываются к конкретному универсальному API файловой системы, предоставляемому ядром.
На самом деле есть много других слоев, которые усложняют
картина в реале. Например ядро пойдет на отлично
попытки кэшировать как можно больше данных с дисков в
иначе свободная память; это дает много преимуществ в скорости. Это
также постарается организовать доступ к устройствам наиболее эффективным образом
возможный; например, пытаясь заказать доступ к диску, чтобы гарантировать данные
хранится физически близко друг к другу, извлекается вместе, даже если
запросы не поступали в последовательном порядке. Далее, многие
устройства относятся к более общему классу, например устройства USB или SCSI.
которые предоставляют свои собственные слои абстракции для записи. Таким образом,
вместо того, чтобы записывать напрямую на устройства, файловые системы
через эти многочисленные слои. Понимание ядра
понять, как эти многочисленные API взаимодействуют и сосуществуют.
3.1 Оболочка
Оболочка — это шлюз для взаимодействия с операционной
система. Будь то баш
, зш
, csh
или любой из многих других
снарядов, все они принципиально имеют только одну главную задачу —
позволяют выполнять программы (вы начнете понимать
как оболочка на самом деле делает это, когда мы говорим о некоторых
внутренности операционной системы позже).
Но оболочки делают гораздо больше, чем позволяют просто выполнить программа. Они обладают мощными способностями перенаправлять файлы, позволяют вам выполнять несколько программ одновременно и скрипт полные программы. Все они возвращаются к все это файл идиома.
3.1.1 Перенаправление
Часто нам не нужны стандартные файловые дескрипторы упоминается в Разделе 3, Дескрипторы файлов, на которые следует указывать их места по умолчанию. Например, вы можете захотеть захватить весь вывод программы в файл на диске или, в качестве альтернативы, пусть он читает свои команды из файла, который вы подготовили раньше. Еще одна полезная задача, возможно, понравится вывод одной программы на вход другой. С операционной системы, оболочка все это облегчает и более.
Table 3.1.1.1 Standard Shell Redirection Facilities
Name | Command | Description | Example |
---|---|---|---|
Redirect to a file | > имя файла | Извлеките весь вывод из стандарта и поместите его в имя файла .![]() >> будет добавлено к
файл, а не перезаписывать его. | лс > имя файла |
Читать из файла | < имя файла | Копировать все данные из файла на стандартный ввод программы | эхо < имя файла |
Труба | программа1 | программа2 | Возьмите все из стандартного из программа1 и передать его
стандартный ввод программа2 | лс | еще |
3.1.2 Реализация
труба
Реализация лс |
more
— еще один пример силы
абстракция. Что принципиально здесь происходит, так это то, что вместо
ассоциации файлового дескриптора для стандартного вывода
с каким-либо базовым устройством (например, консолью, для
вывод на терминал), дескриптор указывает на
буфер в памяти, предоставляемый ядром, обычно называемый труба
. Хитрость здесь в том, что
другой процесс может связать свой стандарт ввод с другой стороны этого же
буфер и эффективно использовать вывод другого
процесс. Это показано на рисунке 3.1.2.1. Труба в действии.
Рисунок 3.1.2.1 Канал в действии
Записи в канал сохраняются ядром до тех пор, пока
соответствующее чтение с другой стороны истощает буфер. Это очень
мощное понятие и является одной из основных форм межпроцессное взаимодействие или IPC в
UNIX-подобные операционные системы. Труба позволяет больше, чем просто
Передача данных; он может действовать как сигнальный канал. Если
процесс считывает
с пустой трубой,
по умолчанию он будет блокировать или будет помещен в
спящий режим до тех пор, пока не будут доступны какие-либо данные (это
обсуждается более подробно в Главе 5, Процесс). Таким образом, два процесса могут использовать конвейер для
сообщить, что какое-то действие было предпринято, просто написав
байт данных; важны не фактические данные, а
просто присутствие любые данные в канале могут
сигнализировать о сообщении. Скажем, например, один процесс запрашивает, что
другой распечатать файл — что-то, что займет некоторое
время. Два процесса могут установить канал между собой
где запрашивающий процесс выполняет
читать
на пустой трубе; существование
пустой, этот вызов блокируется, и процесс не продолжается.
После завершения печати другой процесс может написать сообщение
в трубу, которая эффективно пробуждает запрашивающий
процесс и сигнализирует о том, что работа выполнена.
Разрешение процессам передавать данные друг другу, например это порождает еще одну распространенную идиому UNIX о небольших инструментах, выполняющих одна конкретная вещь. Объединение этих небольших инструментов дает гибкость, которую часто может обеспечить один монолитный инструмент нет.
файловых дескрипторов
файловых дескрипторовОдна из первых вещей, которую узнает программист UNIX, это то, что каждая работающая программа начинается уже с трех файлов открыт:
Таблица 1. 1. Стандартные файлы, предоставляемые Unix
Descriptive Name | File Number | Description |
---|---|---|
Standard In | 0 | Input from the keyboard |
Standard Out | 1 | Output to консоль |
Стандартная ошибка | 2 | Вывод ошибки на консоль |
Рисунок 1.2. Файлы Unix по умолчанию
Возникает вопрос, что такое открытый
файл представляет. Значение, возвращаемое открытый вызов
называется файловый дескриптор и по сути является
index в массив открытых файлов, хранящихся в ядре.
Рисунок 1.3. Абстракция
Файловые дескрипторы являются индексом в
таблица файловых дескрипторов, хранимая ядром. Ядро
создает файловый дескриптор в ответ на открывает вызов
и связывает
файловый дескриптор с некоторой абстракцией базового
файлоподобный объект; будь то реальное аппаратное устройство или
файловая система или что-то еще. Следовательно,
процессы
читают
или запись
вызовов по этой ссылке
что дескриптор файла направляется в правильное место
ядро, чтобы в конечном итоге сделать что-то полезное.
Короче говоря, файловый дескриптор — это ворота в абстракции ядра от базового оборудования. Общий вид абстракция для физических устройств показана на рисунке 1.3, «Абстракция».
Начиная с самого низкого уровня, операционная система требует
программист для создания драйвера устройства , который будет
может обмениваться данными с аппаратным устройством. Этот драйвер устройства
записывается в API, предоставляемом ядром, как в примере 1.2, «Абстракция в include/linux/virtio.h
”; драйвер устройства предоставит
набор функций, которые ядро вызывает в ответ на
различные требования. В приведенном выше упрощенном примере мы можем видеть
водители дают читать
и напишите
функцию которая будет
вызывается в ответ на аналогичные операции над
файловый дескриптор. Драйвер устройства знает, как преобразовать эти
общие запросы в конкретные запросы или команды для
конкретное устройство.
Чтобы обеспечить абстракцию пространства пользователя, ядро
обеспечивает файловый интерфейс через то, что обычно называется уровень устройства . Физические устройства на хосте
представлены файлом в специальной файловой системе, такой как /dev
. В UNIX-подобных системах, поэтому
называемые устройства-узлы имеют то, что называется основной и дополнительный число, которое позволяет ядру связывать определенные узлы
с их базовым драйвером. Их можно определить с помощью ls
, как показано в Примере 1.3, «Пример старшего и младшего чисел».
Пример 1.3. Пример старшего и младшего номеров
$ ls -l /dev/null /dev/zero /dev/tty crw-rw-rw- 1 root root 1, 3 26 августа 13:12 /dev/null crw-rw-rw- 1 root root 5, 0 2 сент.15:06 /dev/tty crw-rw-rw- 1 root root 1, 5 26 августа 13:12 /dev/zero
Это подводит нас к файловому дескриптору, который является дескриптором
пользовательское пространство использует для общения с базовым устройством. В
в широком смысле, что происходит, когда файл open
ed заключается в том, что ядро
используя информацию о пути для сопоставления файлового дескриптора с
то, что обеспечивает соответствующее читать
и пишем
и т.д. API. Когда это открыть
для устройства
( /dev/sr0
выше), майор и
младший номер открытого устройства-узла предоставляет информацию
ядро должно найти правильный драйвер устройства и завершить
отображение. После этого ядро будет знать, как маршрутизировать дальнейшие вызовы.
например прочитать
в базовый
функции, предоставляемые драйвером устройства.
Файл, не являющийся устройством, работает аналогично, хотя есть
больше слоев между ними. Абстракция здесь точка монтирования ; монтирование файловой системы имеет
двойная цель настройки сопоставления, чтобы файловая система знала
базовое устройство, которое обеспечивает хранилище и ядро
знает, что файлы, открытые в этой точке монтирования, должны быть
направляется к драйверу файловой системы. Как и драйверы устройств,
файловые системы записываются в конкретный универсальный API файловой системы
предоставляется ядром.
Действительно есть много других слоев, которые усложняют
картина в реале. Например ядро пойдет на отлично
попытки кэшировать как можно больше данных с дисков в противном случае
свободная память; это дает много преимуществ в скорости. Это также будет
постарайтесь максимально эффективно организовать доступ к устройствам;
например, пытаясь заказать доступ к диску, чтобы гарантировать сохранение данных
физически близкие друг к другу извлекаются вместе, даже если
запросы не поступали в таком порядке. Кроме того, многие устройства
относятся к более общему классу, такому как устройства USB или SCSI, которые
предоставлять свои собственные слои абстракции для записи. Таким образом, скорее
чем запись непосредственно на устройства, файловые системы будут проходить через
эти многочисленные слои. Понимание ядра означает понимание того, как
эти многие API взаимосвязаны и сосуществуют.
Раковина
Оболочка — это шлюз для взаимодействия с операционной
система. Будь то баш
, зш
, csh
или любой из многих других
снарядов, все они принципиально имеют только одну главную задачу -
позволяют выполнять программы (вы начнете понимать
как оболочка на самом деле делает это, когда мы говорим о некоторых
внутренности операционной системы позже).
Но оболочки делают гораздо больше, чем позволяют просто выполнить
программа. Они обладают мощными способностями перенаправлять файлы, позволяют
вам выполнять несколько программ одновременно и скрипт
полные программы. Все они возвращаются к все это файл идиома.
Перенаправление
Часто мы не хотим стандартные файловые дескрипторы, упомянутые в разделе «Файловые дескрипторы», чтобы указать их места по умолчанию. Например, вы можете захотеть захватить все выходные данные программу в файл на диске или, альтернативно, прочитать ее его команды из файла, который вы подготовили ранее. Еще один полезный задача может захотеть передать вывод одной программы на вход другого. В операционной системе оболочка облегчает все это и многое другое.
Таблица 1.2. Standard Shell Redirection Facilities
Name | Command | Description | Example |
---|---|---|---|
Redirect to a file | > filename | Take all output from standard out and поместите его в имя файла .![]() >> будет добавлено к
файл, а не перезаписывать его. | ls > filename |
Read from a file | < filename | Copy all data from the file to the standard input of the program | echo < filename |
Pipe | программа1 | program2 | Взять все из стандартного из program1 и передать его
стандартный ввод программа2 | лс | еще |
Реализация
труба
Реализация лс |
more
— еще один пример силы
абстракция. Что принципиально здесь происходит, так это то, что вместо
ассоциации файлового дескриптора для стандартного вывода
с каким-либо базовым устройством (например, консолью, для
вывод на терминал), дескриптор указывает на
буфер в памяти, предоставляемый ядром, обычно называемый труба
. Хитрость здесь в том, что
другой процесс может связать свой стандарт ввод с другой стороны этого же
буфер и эффективно использовать вывод другого
процесс. Это показано на рисунке 1.4, «Труба в действии» 90 119.
Рисунок 1.4. Канал в действии
Канал — это буфер в памяти, который
связывает два процесса вместе. Пункт файловых дескрипторов
объекту канала, который буферизует отправленные ему данные (через напиши
) быть осушенный (через чтение
)
Запись в канал сохраняется ядром до тех пор, пока
соответствующее чтение с другой стороны истощает буфер. Это очень
мощное понятие и является одной из основных форм межпроцессное взаимодействие или IPC в
UNIX как операционные системы. Труба позволяет больше, чем просто
передача данных; он может действовать как сигнальный канал. Если
процесс
читать
s пусто
pipe, по умолчанию это будет блок или
поместить в спящий режим, пока не будут доступны некоторые данные
(более подробно это обсуждается в главе 5, Процесс . Таким образом, два процесса могут использовать конвейер для
сообщить, что какие-то действия были предприняты, просто написав
байт данных; а не фактические данные важны,
само наличие каких-либо данных в
pipe может сигнализировать о сообщении. Скажем, например, один процесс
просит, чтобы другой распечатал файл - что-то, что
занять некоторое время. Два процесса могут установить канал между
себя, когда запрашивающий процесс выполняет читать
на пустой трубе;
будучи пустым, этот вызов блокируется, и процесс не
Продолжать. После завершения печати другой процесс может
написать сообщение в трубу, которая эффективно просыпается
процесс запроса и сигнализирует о том, что работа выполнена.
Разрешение прохождения процессов данные друг с другом, как это приводит к еще одному общему Идиома UNIX о небольших инструментах, выполняющих одну конкретную задачу. Объединение этих небольших инструментов в цепочку обеспечивает гибкость, монолитный инструмент часто не может.
Включите JavaScript для просмотра комментариев на базе Disqus.comments на основе Disqusфайловых дескрипторов — CS 61
Вот краткое введение в файловые дескрипторы для CS 61.
Другую презентацию этого материала см. глава 10, особенно через раздел 10.5. Раздел 10.4.2 может быть особенно интересно для набора задач 4!
Дескриптор файла является абстракцией Unix для открытого ввода/вывода поток: файл, сетевое соединение, канал (канал связи между процессами), терминал и т. д.
Таким образом, файловый дескриптор Unix занимает ту же нишу, что и stdio FILE*
.
Однако в то время как FILE*
(например, stdin
или stdout
) является указателем на
некоторая объектная структура, файловый дескриптор — это просто целое число. За
например, 0, 1 и 2 — версии файлового дескриптора
stdin
, stdout
и stderr
соответственно.
(Используются целые числа, потому что ядру операционной системы проще
проверить, чем произвольные указатели. Хотя в ядре есть объекты несколько
похоже на FILE*
s, это не дает приложениям прямого доступа к этим
объекты. Вместо этого в массиве, называемом таблицей файловых дескрипторов , хранится
массив таких объектов. Файловые дескрипторы, которыми манипулируют приложения, индексирует в этой таблице. Очень легко проверить, что целое число находится в
границ.)
Логически, файловый дескриптор содержит ссылку на файл , которая представляет
базовые данные (например, /home/kohler/grades.txt
) и файл
position , что является смещением в файле. файлов может быть много
дескрипторы одновременно открыты для одной и той же ссылки на файл, каждый с
разное положение. Для файлов на диске положение может быть изменено явно:
процесс может перематывать и перечитывать часть файла, например, или пропускать, как
мы видели с пошаговыми шаблонами ввода-вывода. Эти файлы называются с возможностью поиска . Однако,
не все типы файловых дескрипторов доступны для поиска. Большинство каналов связи
между процессами нет, как и с сетевыми каналами.
Системные вызовы файлового дескриптора
Вы будете использовать следующие системные вызовы в задании 3. Вы можете прочитать
о них подробно с помощью man
: например, man 2 open
, man 2 read
, man 2 lseek
. « 2
» означает «расскажи мне о системном вызове».
Или вы можете проверить книгу.
open
int open(const char* pathname, int flags, [mode_t mode])
Открыть файл путь
в соответствии с режимом
, который содержит набор флагов
ровно один из O_RDONLY
(открыт для чтения), O_WRONLY
(открыт для записи),
и O_RDWR
(открыт как для чтения, так и для записи), а также другие необязательные
флаги. Возвращает файловый дескриптор для открытого файла или -1 в случае ошибки.
Другие важные флаги включают:
-
O_CREAT
: Создать файл, если он не существует, используя аргумент режима . чтобы установить начальные права доступа к файлу. (обычнорежим
аргумент будет быть0660
илиS_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
, который позволяет текущий пользователь и группа для чтения или записи файла. -
O_CREAT | O_EXCL
: Создать файл и завершиться ошибкой, если файл уже существует. -
O_APPEND
: Открыть файл в режиме добавления: каждыезаписи
автоматически перескакивают в конец файла и делает файл длиннее. -
O_TRUNC
: Обрезать файл до длины 0,
Читать
SSIZE_T Read (int fd, char* buf, size_t sz)
Считается по сравнению с SZ
Bufftes от Decriptor FD
. Возвращает количество прочитанных байтов, если таковые имеются. Возвращает 0 в конце файла и
-1
при ошибке.
Обычно при чтении
возвращает sz
, но может возвращать и меньшее значение. Например,
в файле может остаться всего sz - 2
байта, а может быть только
быть sz - 10
байт доступно для чтения на данный момент. читается как
, что
возвращает меньше запрошенного количества байтов, называется коротким читать .
Если sz > 0
, то возвращаемое значение 0 является надежным концом файла
индикатор. Например, при чтении канала 0 означает другой конец канала.
труба закрылась. Другие короткие чтения: , а не , надежный конец файла.
индикаторы. Например, при чтении с терминала чтение 1024
bytes может вернуть 1 байт, потому что пользователь пока ввел только 1 байт;
в будущем пользователь может ввести больше байтов.
Возвращаемое значение -1
указывает на ошибку , а означает, что ни один байт не был
читать. Если были прочитаны какие-либо байты, возвращаемое значение будет больше 0.
Однако не все ошибки одинаково серьезны.
Постоянные ошибки
Системные вызовы чтения
и записи
, а также некоторые другие системные вызовы
так называемые «медленные» системные вызовы , которые могут возвращать различные классы ошибок.
Некоторые серьезные ошибки указывают на проблемы с базовым файлом. За
например, Ошибка EIO
указывает на повреждение диска, а ENOSPC
указывает
что диск заполнен. Эти ошибки, которые мы будем называть постоянными ошибками ,
должны быть возвращены пользователю.
Прочие, перезапускаемые ошибки несерьезны; они возвращаются для спец.
причины (мы обсудим эти причины) и по возможности должны быть замаскированы (скрыта от пользователя). Это ошибки EINTR
и (иногда) EAGAIN
.
Коды ошибок типа EIO
и EINTR
определены в #include
. Когда
системный вызов возвращает ошибку, обычно он возвращает -1; код ошибки
возвращается в специальной глобальной переменной с именем errno
.
На каждой странице руководства по системным вызовам перечислены все ошибки, которые могут возникнуть в этой системе.
вызов. Прочтите эту страницу для чтения, взглянув на read(2)
. (Эта запись означает
«страница для чтения в разделе 2 руководства»; выполнить [женщина] мужчина 2 прочитать
.)
Напишите
SSIZE_T Запись (int fd, const char* buf, size_t sz)
Напишите большую часть SZ
Bufftes to Decriptor FD
. .
Возвращает количество записанных байтов, если они есть. Возвращает -1
в случае ошибки.
Обычно запись
возвращает sz
, но, как и чтение
, может возвращаться
меньше: короткая запись . Например, может быть место только для `sz
- 2` байта на диске, или чтение процесса из канала может быть
позади, или сигнал может прервать запись на полпути.
Возвращаемое значение -1
указывает на ошибку , а означает, что ни один байт не был
написано. Если были записаны какие-либо байты, возвращаемое значение будет больше
чем 0.
lseek
off_t lseek(int fd, off_t pos, int откуда)
Изменить дескриптор файла fd 9позицию 0174 и вернуть результирующую позицию
относительно начала файла. Есть три важных значения для
откуда
:
-
SEEK_SET
: Установите позицию в файле наpos
.pos == 0
устанавливает позицию на начало файла,pos == 1
устанавливает его на один байт и так далее. -
SEEK_CUR
: изменить позицию файла относительно текущей позиции.pos == 0
оставляет позицию без изменений,pos == 10
пропускает следующие 10 байт и так далее. -
SEEK_END
: Установите положение файла относительно размера файла.поз == 0
наборов позиция в конец файла,pos == -1
устанавливает его в последний байт в файл и так далее.
Итак, lseek(fd, 0, SEEK_CUR)
возвращает текущую позицию без ее изменения.
Возвращает -1
при ошибке, которая может произойти, например, если файл не
доступен для поиска или новая позиция в файле находится вне допустимого диапазона для файла.
close
int close(int fd)
Закрыть дескриптор файла.
Понимание ошибок
Соглашение об ошибках Unix заключается в том, что системные вызовы возвращают -1
при ошибке. А
затем устанавливается глобальная переменная int errno
, чтобы программа могла сказать, что
произошла какая-то ошибка. Заголовочный файл
определяет символьные
имена для конкретных условий ошибки. Каждое имя начинается с E
. За
Например, система вызывает выше «return EBADF
, если fd
не является открытым
файловый дескриптор». Фактически это означает, что системный вызов возвращает
значение
-1
(приведение к соответствующему типу), а глобальный errno
переменная установлена на константу EBADF
.
Библиотечная функция const char* strerror(int errnum)
возвращает
текстовая строка, описывающая константу ошибки. Например, strerror(EINVAL)
возвращает "Недопустимый аргумент"
. Это может быть полезно
для отладки.
На странице руководства системного вызова будет список ошибок, которые он может вернуть.
Дополнительные системные вызовы
Следующие системные вызовы также могут быть полезны для набора задач 4, в зависимости от вашей реализации стратегия. Прочтите их справочные страницы, обратитесь к CS:APP3e или нашему раздаточному материалу. код или свяжитесь с Piazza для получения дополнительной информации.
void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
Сопоставление памяти части файла с возвратом сопоставленного адреса.Возвращает
MAP_FAILED == (void*) -1
при ошибке. Не работает для всех типы файлов.int munmap(void* addr, size_t len)
Отменить сопоставление ранее сопоставленной области памяти.int madvise(void* addr, size_t len, int совета)
Предоставление рекомендаций по предварительной выборке для части отображаемой в памяти области.int posix_fadvise(int fd, off_t pos, off_t len, int совета)
Предоставить совет по предварительной выборке для части файлового дескриптора.
Ядро — мой друг. Часть 1. Развлечение с файловыми дескрипторами | Вишну Бхарати | HackerNoon.com
Фото Roderico Y. Díaz на Unsplash. Это напоминает мне о временах, когда я выполнял команду ls /proc в своем терминале.Развлечение с файловыми дескрипторами
В начале 2018 года я хотел узнать в общих чертах о Linux и системном программировании. То есть дружить с Ядром! Итак, я начал читать The Linux Programming Interface. Это первая часть серии сообщений в блоге, которые я буду писать по мере изучения книги и разгадывания тайн Linux.
Этот пост является попыткой понять некоторые части урока «Файловый ввод-вывод: универсальная модель ввода-вывода» из Интерфейса программирования Linux.
Типы файлов
Я слышал утверждение, что «все в Linux является файлом». Но я узнал, что в Linux есть разные типы файлов.
Системные вызовы
Системный вызов — это способ попросить ядро сделать за нас некоторую работу. Например, это четыре основных системных вызова, которые помогают работать с файлами в Linux 9.0119
- открыть — Эй, ядро, не могли бы вы открыть для меня файл? Чтобы процесс мог что-то с ним сделать.
- read — Эй, ядро, не могли бы вы прочитать этот удивительный фрагмент кода, который я сохранил в
~/cool/stuff/is/here.js
? - write — Эй, ядро, не могли бы вы помочь мне записать мою очень длинную домашнюю работу в этот файл?
- закрыть — Эй, ядро, я сделал домашнее задание, пожалуйста, закройте файл.
Мы будем тусоваться и делать другие забавные вещи.
Файловые дескрипторы
Дескриптор файла — это неотрицательное целое число, которое используется для ссылки на файл.
Когда системный вызов open()
вызывается процессом, от него возвращается дескриптор файла, который можно использовать в других системных вызовах, таких как чтение, запись, закрытие.
Одна из интересных вещей, которую я упустил из виду, когда читал урок в первый раз, это (это, вероятно, важный ключевой вывод)
Каждый процесс имеет свой собственный набор файловых дескрипторов
Давайте попробуем понять это шаг за шагом.
Один процесс, один файл
Давайте напишем программу, которая просто открывает файл и печатает значение его файлового дескриптора.
Я создал двоичный файл и выполнил его для чтения одного файла за раз. Таким образом, это в основном чтение одного файла из одного процесса за раз.
Файл всегда получает значение дескриптора файла 3 всегдаОдин процесс, несколько файлов
Теперь давайте попробуем открыть несколько файлов из одного процесса одновременно
файлы были размещены с последовательными целочисленными значениями Способ, которым файлы получают номер файлового дескриптора, основан на этой простой идее процесс.
— Керриск, Майкл. Интерфейс программирования Linux: Справочник по системному программированию Linux и UNIX (стр. 73). Без Крахмального Пресса. Киндл издание.
Несколько процессов, несколько файлов
Это самое интересное. Что произойдет, если к одним и тем же файлам одновременно будут обращаться несколько процессов. Как тогда распределяется файловый дескриптор?
Нумерация выполняется на уровне процессаЭто подтверждает утверждение, с которого мы начали,
Каждый процесс имеет свой собственный набор файловых дескрипторов
Процесс 9012 открыт 1.js
назначение fd 3 и 2.js
назначение fd 4. Процесс 9015 ничем не отличается, он делал то же самое. Потому что это значение неиспользуемого файлового дескриптора с наименьшим номером в этих процессах.
Теперь, когда мы прошли этот долгий путь, у меня возникает интересный вопрос: что произойдет, если два процесса попытаются записать в открытые файлы одновременно. (Наверное, на это стоит ответить в другой раз!)
Стандартные файловые дескрипторы
Я уже слышал об этих именах и, к моему удивлению, это всего лишь файловые дескрипторы.
Создается впечатление, что при создании процесса он автоматически открывает файлы stdin, stdout и stderr и присваивает им номера fd 0,1,2 соответственно.
Я сделал еще один шаг и попытался увидеть, где находятся эти файлы. Но у меня получилось то, чего я еще не знаю. (Удивительно! Нам есть о чем задуматься)
персонаж особенный? ¯\_(ツ)_/¯Загадки
- Что произойдет, если два процесса попытаются прочитать из открытого файла одновременно?
- Что произойдет, если два процесса одновременно попытаются записать в открытый файл?
- Что такое
/dev/pts/0
? - Что такое тип файла «специальный символ»?
(Пожалуйста, прокомментируйте, если у вас есть возможность решить их)
Спасибо за чтение. Я цитирую стихи из моей любимой тамильской литературы «Tirukkuṛaḷ» в конце своих сообщений в блоге.
செய்தக்க செயக்கெடும் செயக்கெடும் செய்தக்க
செய்யாமை கெடும் கெடும்.
— திருக்குறள்
Переводное значение (моими словами): Дела идут не так у людей, которые делают то, что им делать не положено, а также у людей, которые не делают того, что от них ожидают. .
Исследование файловых дескрипторов процессов Linux для реагирования на инциденты и криминалистики
Давайте поговорим о файловых дескрипторах Linux и о том, как исследовать вредоносный процесс, использующий их.
Что такое файловый дескриптор? С момента создания Unix (на котором основана Linux) все представляет собой файл. Мы можем спорить о деталях, но в основном это правда, и для наших целей это все, что нам нужно знать. Дескриптор файла – это дескриптор, используемый операционной системой для доступа к файлу или другому механизму ввода-вывода. Это то же самое, что и телефонный номер, который вы набираете, чтобы связаться с конкретным человеком, за исключением того, что в Linux этот номер даст вам указатель на файл.
Мы упрощаем это для нашего обсуждения, но просто знайте, что в основном все запущенные процессы в Linux будут иметь какой-то открытый файловый дескриптор. Эти файловые дескрипторы могут быть любым допустимым файлом или ресурсом в Linux, например:
- Файлы
- Сетевые сокеты
- Именованные каналы
- Устройства
В Linux самые основные файловые дескрипторы, которые вы увидите открытыми для большинства процессов, будут stdin, stdout и stderr . Они позволяют процессу обмениваться данными с терминалом и принимать ввод данных ( stdin ), выводить данные на терминал ( stdout ) и передавать ошибки ( stderr ). Но более того, файловые дескрипторы также покажут, с какими файлами, сокетами и т. д. может разговаривать процесс во время работы. Часто живое вредоносное ПО записывает данные на диск, который оно крадет или использует по другим причинам (например, в журналы данных).
Ключевым моментом здесь является то, что если процесс запущен, вы можете быстро увидеть, какие файлы он открыл, и можете использовать эту информацию, чтобы определить, является ли он вредоносным и что он может делать.
Чтобы найти дескрипторы открытых файлов процесса, мы обратимся к нашему старому другу — файловой системе /proc . Данные, которые нам нужны, находятся здесь:
/proc/
Основной формат для перечисления дескрипторов открытых файлов процесса:
ls -al /proc/
Как только вы это сделаете, вы увидите, какие файлы были открыты процессом и интересны ли они.
Пример подозрительного процесса LinuxНиже мы видим подозрительный процесс с именем tmpwrk , который проявляет особый интерес к файлу в каталоге /tmp . Мы можем использовать эту информацию для просмотра содержимого этого файла и определения того, что может происходить.
Мы смотрим в каталог /proc/
Мы видим, что файл и сокет открыты. У файла очень странное имя /tmp/.data и мы хотим посмотреть, что это такое. Мы можем использовать стандартные файловые инструменты для самой ссылки на файл или файла, на который она ссылается напрямую.
Ниже мы cat извлекаем файл и видим, что он содержит некоторые секретные данные. Это может помочь подтвердить, что двоичный файл действительно является вредоносным. Мы можем просматривать файл, копировать его, запускать хэши или что-то еще. Это стандартный файл.
Как насчет открытого сокета?Открытый сокет также можно исследовать, используя число в [квадратных скобках], которое равно индекс . Вы можете запустить его через netstat различными способами. Эндрю Кейс написал в Твиттере эту команду:
netstat -eepan | grep
Где INODE снова число в квадратных скобках сверху. Это покажет вам тип сокета, который использует процесс (например, сеть).
Что насчет lsof? lsof — это инструмент, который показывает все открытые файлы в системе. Если он не установлен, вам придется использовать методы, описанные выше. Вы можете использовать lsof со следующим:
lsof -p
lsof -c <имя команды>
Команда lsof покажет все открытые файлы одним простым в использовании способом.
Почему бы не использовать lsof?Есть две причины, по которым использование lsof может быть не первым, что нужно делать при поиске подозрительного процесса:
- Он может быть не установлен, и вы не хотите изменять скомпрометированную машину, загружая новые пакеты .
- Команда lsof обычно не вызывается и может предупредить вредоносное ПО или злоумышленника о присутствии следователей.
Последний пункт может быть немного академическим, но более простые команды ls и cat очень распространены, и трудно сказать, почему они могут использоваться. lsof , с другой стороны, довольно специфичен, и всегда есть вероятность того, что на него нацелено вредоносное ПО, чтобы избежать обнаружения или того хуже.