Какой номер дескриптора получит файл file2 в таком случае cat file1 sort file2
Просмотреть содержимое директорий /etc, /proc, /home. Посмотреть пару произвольных файлов в /etc.
- Используя команду ls /$DIRNAME просматриваем содержимое директории. Команда cat /etc/$FILENAME позволяет просмотреть файлы
Выяснить, для чего предназначена команда cat. Используя данную команду, создать два файла с данными, а затем объединить их. Просмотреть содержимое созданного файла. Переименовать файл, дав ему новое имя.
Создать несколько файлов. Создать директорию, переместить файл туда. Удалить все созданные в этом и предыдущем задании директории и файлы.
- Переместить файл в директорию можно командой mv $FILENAME $DIRNAME . Удаляем все файлы командой rm -r находясь в директории практического занятия
В ОС Linux скрытыми файлами считаются те, имена которых начинаются с символа “.”. Сколько скрытых файлов в вашем домашнем каталоге? (Использовать конвейер. Подсказка: для подсчета количества строк можно использовать wc.)
- Конвейер ls -ld .?* | wc -l выведет количество скрытых файлов в текущей директории, в моем домашнем каталоге их 16
- Командой cat /etc/* 2> catalogs отправляем ошибочные выводы в файл "catalogs", потом считаем строки в файле wc -l catalogs . У меня вышло 126
Запустить в одном терминале программу, а в другом терминале посмотреть PID процесса и остановить с помощью kill, посылая разные типы сигналов. Что происходит?
- В зависимости от типа сигнала процесс переходит в определенный статус, например kill -9 $PID завершит процесс сразу
Отобразить в /dev список устройств, которые в настоящее время используются вашим UID (для этого используется команда lsof). Организовать конвейер через less, чтобы посмотреть их должным образом.
Cоздать директорию для хранения фотографий. В ней должны быть директории по годам (например, за последние 5 лет), и в каждой директории года — по директории для каждого месяца.
Заполнить директории файлами вида ГГГГММДДНН.txt. Внутри файла должно быть его имя. Например: 2018011301.txt, 2018011302.txt.
- Используем команду ls -lA в сочетании с конвейером для выполнения условий задания. Вывод:
- добавляем |wc -l и подстчет выдает нам 10 типов разрешений
Файлы и права доступа в Linux
Создать файл file1 и наполнить его произвольным содержимым. Скопировать его в file2. Создать символическую ссылку file3 на file1. Создать жесткую ссылку file4 на file1. Посмотреть, какие айноды у файлов. Удалить file1. Что стало с остальными созданными файлами? Попробовать вывести их на экран.
- Файлы file1 и file4 будут иметь одинаковые айноды. После удаления останутся все файлы, кроме file1, при этом символическая ссылка будет битой, а при входе по ней в текстовый редактор будет создан новый файл file1.
Дать созданным файлам другие, произвольные имена. Создать новую символическую ссылку. Переместить ссылки в другую директорию.
- Как от переименования, так и от перемещения пострадают только символьные ссылки, так как они будут ссылаться или не натот файл, или не по тому пути.
Создать два произвольных файла. Первому присвоить права на чтение, запись для владельца и группы, только на чтение — для всех. Второму присвоить права на чтение, запись — только для владельца. Сделать это в численном и символьном виде.
- chmod 664 file1 && chmod 644 file2 в числовом виде и chmod ug=rw,o=r file1 && chmod u=rw,og=r file2 в символьном(можно также использовать +-, если известны права доступа).
Создать пользователя, обладающего возможностью выполнять действия от имени суперпользователя.
- на выбор useradd или adduser быстрее всего сделать одной командой useradd -m -G sudo -s /bin/bash adminuser
Создать группу developer и несколько пользователей, входящих в нее. Создать директорию для совместной работы. Сделать так, чтобы созданные одними пользователями файлы могли изменять другие пользователи этой группы.
- Создаем группу командой groupadd developer , затем создаем новых пользователей командами из предыдущей задачи указав необходиму группу или добавляем существующих пользователей в группу при помощи usermod -aG developer $USERNAME . На каталоге меняем группу рекурсивно chgrp -R developer , затем меняем права chmod -R 2775 newpol 2 - setGID означает, что все новые файлы наследуют группу каталога.
Создать в директории для совместной работы поддиректорию для обмена файлами, но чтобы удалять файлы могли только их создатели.
- Если добавить атрибут t на каталог, то удалить файлы из него смогут только владельцы
Создать директорию, в которой есть несколько файлов. Сделать так, чтобы открыть файлы можно было, только зная имя файла, а через ls список файлов посмотреть было нельзя.
Bash, скрипты и автоматизация
Написать скрипт, который удаляет из текстового файла пустые строки и заменяет маленькие символы на большие (воспользуйтесь tr или sed).
- Скрипт chscript.sh для выполнения указанной задачи добавлен в репозиторий
Создать скрипт, который создаст директории для нескольких годов (2010 — 2017), в них — поддиректории для месяцев (от 01 до 12), и в каждый из них запишет несколько файлов с произвольными записями (например, 001.txt, содержащий текст«Файл 001», 002.txt с текстом Файл 002) и т. д.
- Скрипт dirmaker.sh для выполнения указанной задачи добавлен в репозиторий
Создать файл crontab, который ежедневно регистрирует занятое каждым пользователем дисковое пространство в его домашней директории.
- Задачу cron нужно запустить от root пользователя, чтобы иметь доступ ко всем данным. Строка команды в crontab будет выглядеть так @daily date >> /var/log/diskspacemonitor; du -hs /home/* >> /var/log/diskspacemonitor
Создать скрипт ownersort.sh, который в заданной папке копирует файлы в директории, названные по имени владельца каждого файла. Учтите, что файл должен принадлежать соответствующему владельцу.
- Скрипт ownersort.sh добавлен в репозиторий, настроен на копирование без рекурсии, для копирования всех файлов убрать -maxdepth 1 из параметров
Сетевые возможности Linux
Произвести ручную настройку сети в Ubuntu.
- задаем адрес c помощью ifconfig предварительно установив пакет net-tools. ifconfig eth0 10.10.10.10 netmask 255.255.255.0 , затем добавляем роут route add default gw 10.10.10.1 eth0
Переключить настройку сети на автоматическую через DHCP, проверить получение адреса.
- переходим в директорию /etc/network/interfaces прописываем следующие строки и перезапускаем службу networking
- Способов несколько, один из них добавление в /etc/network/interfaces строки dns-nameservers 1.1.1.1 , я отредактировал файл /etc/resov.conf, до перезагрузки будут действовать установленные настройки
Настроить правила iptables, чтобы из внешней сети можно было обратиться только к портам 80 и 443.
- Очищаем текущие правила приема iptables -F INPUT добавляем новые
Дополнительно к предыдущему заданию настроить доступ по ssh только из указанной сети.
Правильные ответы выделены зелёным цветом.
Все ответы: В курсе даются основные понятия операционной системы Linux и важнейшие навыки работы в ней. Изложение сопровождается большим количеством практических примеров. Данный курс может рассматриваться как учебник для студентов, начинающих обучение по специальностям в области информатики и ещё не знакомых с ОС Linux.
(1) Аппаратно реализованная часть загрузки системы, в отличие от вторичного загрузчика, реализованного программно
(3) Программа, работающая со стартовым виртуальным диском, в отличие от вторичного загрузчика, работающего с полным вариантом системы
(4) Маленькая программа в заранее известном месте диска, задача которой — найти и загрузить вторичный загрузчик
(3) Класс объектов файловой системы, обмен данными с которыми не приводит к обращению к содержимому какого-либо определённого файла
(1) Интерпретировать данные более высокого уровня независимо от того, каким способом они были получены на более низком уровне
(2) Клиент Secure Shell на рабочей станции и текстовый редактор ( vim , ncedit или joe ) на удалённом компьютере
(3) UID и GID объекта, список GID, членом которых является хозяин объекта, тип объекта и его атрибуты
(2) связанная пара дескрипторов, где данные, записанные на входной дескриптор, сразу доступны для чтения с выходного
(1) Изменять настройки некоторой службы или последовательность выполнения некоторых сценариев без редактирования файлов
(4) Любых файлов, не попадающих по классификации FHS в специальные каталоги /lib , /var , /bin и т. п.
(1) Понятие «цепочка» использовалось только в предыдущей версии межсетевого экрана Linux — ipchains . В iptables его заменили более общим понятием «таблица»
(2) Таблицы и цепочки следуют попеременно в произвольном порядке; по действию ACCEPT пакет может покинуть таблицу, но не цепочку
(4) Таблицы iptables состоят из нескольких цепочек; покидая одну цепочку, пакет направляется в другую
(2) основана на алгоритме обработки шаблонов, однако имеет отличия, связанные со спецификой работы с файлами
(4) использует алгоритм «globbing», который, в отличие от генерации имён файлов в более ранних версиях shell, не основан на понятии «шаблон»
Как, редактируя текст в Vim/Vi, сохранить текст от курсора до конца текущей строки и записать сохранённый фрагмент в самый конец файла?
(2) С журналами работают различные программы, однако эта работа управляется единым файлом /etc/syslog.conf
(3) Сервер — тот, кто устанавливает соединение, клиент — тот, кто пользуется установленным соединением
(1) Регламентируют доступ к почтовому ящику, при этом SMTP не требует идентификации пользователя, а POP3, в отличие от IMAP4, поддерживает создание пользователем почтовых ящиков на сервере
(4) запуск X-сервера и затем X-приложений, указанных в сценарии .xinitrc пользователя, системном сценарии xinitrc или в командной строке
(4) Достигается очень высокий процент сжатия, но получившийся файл неудобно передавать по каналам с ограниченной пропускной способностью из-за неравномерности сжатия
(1) появились пользователи, желающие установить скомпилированное ядро Linux и набор утилит на свой компьютер
В каком каталоге содержатся файлы, которые не могут совместно использоваться несколькими компьютерами в сети:
Пусть [methody@localhost methody]$ ls -li examples/text text-hardlink text-symlink 127705 -rw-r--r-- 2 methody methody 653 Сен 30 10:04 examples/text 127705 -rw-r--r-- 2 methody methody 653 Сен 30 10:04 text-hardlink 3621 lrwxrwxrwx 1 methody methody 13 Окт 4 18:05 text-symlink -> examples/text К чему приведёт выполнение команды rm examples/text ?
(3) возможность просматривать только содержимое файлов в каталоге, но не самого каталога (имена файлов в этом случае надо знать заранее)
(1) Пользователь lead (при условии, что он не является членом группы zinc ) — на запись, чтение и выполнение, члены группы zinc — на чтение и выполнение, прочие — на выполнение
(2) Пользователи lead и zinc — на запись, чтение и выполнение (при условии, что они принадлежат группе tin , в противном случае — на чтение и выполнение), все остальные — на выполнение
(3) Пользователь lead — на запись, чтение и выполнение, члены группы zinc — на чтение и выполнение, прочие — на выполнение
(4) Пользователь lead — на запись, чтение и выполнение, члены группы zinc — на чтение и выполнение (доступ на выполнение без доступа на чтение не имеет смысла)
Как, редактируя текст в Emacs, вырезать текущий абзац (в котором находится точка) и вставить его в самый конец текста?
Однажды, на одном интервью меня спросили, что ты будешь делать, если обнаружишь неработающий сервис из-за того, что на диске закончилось место?
Конечно же я ответил, что посмотрю, чем занято это место и если возможно, то почищу место.
Тогда интервьюер спросил, а что если на разделе нет свободного места, но и файлов, которые бы занимали все место, ты тоже не видишь?
На это я сказал, что всегда можно посмотреть открытые файл дескрипторы, например командой lsof и понять какое приложение заняло все доступное место, а дальше можно действовать по обстоятельствам, в зависимости от того, нужны ли данные.
Интервьюер прервал меня на последнем слове, дополнив свой вопрос: «Предположим, что данные нам не нужны, это просто дебаг лог, но приложение не работает из-за того, что не может записать дебаг»?
«окей», — ответил я, «мы можем выключить дебаг в конфиге приложения и перезапустить его».
Интервьюер возразил: «Нет, приложение мы перезапустить не можем, у нас в памяти все еще хранятся важные данные, а к самому сервису подключены важные клиенты, которых мы не можем заставлять переподключаться заново».
«ну хорошо», сказал я, «если мы не можем перезапускать приложение и данные нам не важны, то мы можем просто очистить этот открытый файл через файл дескриптор, даже если мы его не видим в команде ls на файловой системе».
Интервьюер остался доволен, а я нет.
Тогда я подумал, почему человек, проверяющий мои знания, не копает глубже? А что, если данные все-таки важны? Что если мы не можем перезапускать процесс, и при этом этот процесс пишет на файловую систему в раздел, на котором нет свободного места? Что если мы не можем потерять не только уже записанные данные, но и те данные, что этот процесс пишет или пытается записать?
Создание собственного перенаправления вывода
Перенаправляя ввод и вывод в сценариях, вы не ограничены тремя стандартными дескрипторами файлов. Как уже говорилось, можно иметь до девяти открытых дескрипторов. Остальные шесть, с номерами от 3 до 8, можно использовать для перенаправления ввода или вывода. Любой из них можно назначить файлу и использовать в коде скрипта.
Назначить дескриптор для вывода данных можно, используя команду exec :
После запуска скрипта часть вывода попадёт на экран, часть — в файл с дескриптором 3 .
Перенаправление вывода, используя собственный дескриптор
▍Временное перенаправление вывода
Если запустить скрипт, обе строки попадут на экран, так как, как вы уже знаете, по умолчанию ошибки выводятся туда же, куда и обычные данные.
Временное перенаправление
Запустим скрипт так, чтобы вывод STDERR попадал в файл.
Файловые дескрипторы
Файловый дескриптор — это неотрицательное число, которое является идентификатором какого-либо потока ввода-вывода, который может быть связан с файлами, каталогами или сокетами.
В системной файловой таблице (SFT — System File Table) и таблице индексных дескрипторов (INode Table) содержится информация, необходимая для доступа процесса к данным файла. Если несколько процессов запрашивают доступ к одному и тому же файлу, то каждый из тих процессов получит собственный элемент системной файловой таблицы, несмотря на то что они будут работать с одним и тем же файлом.
Ядро предоставляет процессу файловый дескриптор, когда тот получает доступ к файлу. Можно сказать, что файловый дескриптор — это индекс массива открытых файлов, который является уникальным для каждого процесса. Но первые три индекса жестко закреплены:
- 0 — стандартный ввод (stdin);
- 1 — стандартным выводом (stdout);
- 2 — стандартный поток ошибок (stderr).
Создание дескрипторов файлов для ввода данных
После окончания чтения файла можно восстановить STDIN и пользоваться им как обычно:
Перенаправление ввода
В этом примере дескриптор файла 6 использовался для хранения ссылки на STDIN . Затем было сделано перенаправление ввода, источником данных для STDIN стал файл. После этого входные данные для команды read поступали из перенаправленного STDIN , то есть из файла.
После чтения файла мы возвращаем STDIN в исходное состояние, перенаправляя его в дескриптор 6 . Теперь, для того, чтобы проверить, что всё работает правильно, скрипт задаёт пользователю вопрос, ожидает ввода с клавиатуры и обрабатывает то, что введено.
Подавление вывода
Тот же подход используется, если, например, надо очистить файл, не удаляя его:
Тузик
В начале моей карьеры я пытался создать небольшое приложение, в котором нужно было хранить информацию о пользователях. И тогда я думал, а как мне сопоставить пользователя к его данным. Есть, например, у меня Иванов Иван Иваныч, и есть у него какие-то данные, но как их подружить? Я могу указать напрямую, что собака по имени «Тузик» принадлежит этому самому Ивану. Но что, если он сменит имя и вместо Ивана станет, например, Олей? Тогда получится, что наша Оля Ивановна Иванова больше не будет иметь собаки, а наш Тузик все еще будет принадлежать несуществующему Ивану. Решить эту проблему помогла база данных, которая каждому пользователю давала уникальный идентификатор (ID), и мой Тузик привязывался к этому ID, который, по сути, был просто порядковым номером. Таким образом хозяин у тузика был с ID под номером 2, и на какой-то момент времени под этим ID был Иван, а потом под этим же ID стала Оля. Проблема человечества и животноводства была практически решена.
Получение сведений об открытых дескрипторах
Для того, чтобы получить список всех открытых в Linux дескрипторов, можно воспользоваться командой lsof . Во многих дистрибутивах, вроде Fedora, утилита lsof находится в /usr/sbin . Эта команда весьма полезна, так как она выводит сведения о каждом дескрипторе, открытом в системе. Сюда входит и то, что открыли процессы, выполняемые в фоне, и то, что открыто пользователями, вошедшими в систему.
У этой команды есть множество ключей, рассмотрим самые важные.
- -p Позволяет указать ID процесса.
- -d Позволяет указать номер дескриптора, о котором надо получить сведения.
Ключ -a используется для выполнения операции логического И над результатами, возвращёнными благодаря использованию двух других ключей:
Вывод сведений об открытых дескрипторах
Тип файлов, связанных с STDIN , STDOUT и STDERR — CHR (character mode, символьный режим). Так как все они указывают на терминал, имя файла соответствует имени устройства, назначенного терминалу. Все три стандартных файла доступны и для чтения, и для записи.
Посмотрим на вызов команды lsof из скрипта, в котором открыты, в дополнение к стандартным, другие дескрипторы:
Вот что получится, если этот скрипт запустить.
Просмотр дескрипторов файлов, открытых скриптом
Скрипт открыл два дескриптора для вывода ( 3 и 6 ) и один — для ввода ( 7 ). Тут же показаны и пути к файлам, использованных для настройки дескрипторов.
▍Постоянное перенаправление вывода
Если в скрипте нужно перенаправлять много выводимых на экран данных, добавлять соответствующую команду к каждому вызову echo неудобно. Вместо этого можно задать перенаправление вывода в определённый дескриптор на время выполнения скрипта, воспользовавшись командой exec :
Перенаправление всего вывода в файл
Если просмотреть файл, указанный в команде перенаправления вывода, окажется, что всё, что выводилось командами echo , попало в этот файл.
Команду exec можно использовать не только в начале скрипта, но и в других местах:
Вот что получится после запуска скрипта и просмотра файлов, в которые мы перенаправляли вывод.
Перенаправление вывода в разные файлы
Сначала команда exec задаёт перенаправление вывода из STDERR в файл myerror . Затем вывод нескольких команд echo отправляется в STDOUT и выводится на экран. После этого команда exec задаёт отправку того, что попадает в STDOUT , в файл myfile , и, наконец, мы пользуемся командой перенаправления в STDERR в команде echo , что приводит к записи соответствующей строки в файл myerror.
Освоив это, вы сможете перенаправлять вывод туда, куда нужно. Теперь поговорим о перенаправлении ввода.
Стандартные дескрипторы файлов
Всё в Linux — это файлы, в том числе — ввод и вывод. Операционная система идентифицирует файлы с использованием дескрипторов.
Каждому процессу позволено иметь до девяти открытых дескрипторов файлов. Оболочка bash резервирует первые три дескриптора с идентификаторами 0, 1 и 2. Вот что они означают.
- 0 , STDIN — стандартный поток ввода.
- 1 , STDOUT — стандартный поток вывода.
- 2 , STDERR — стандартный поток ошибок.
STDERR
Немного усложним задачу
Представим, что данные нам важны, но места на диске у нас нет ни в одном из разделов и подключить диск мы не можем.
Перезапускаем приложение, и проверяем:
Места на диске нет, но мы успешно создаем там именованный pipe:
Теперь нам надо как-то завернуть все данные, что попадают в этот pipe на другой сервер через сеть, для этого подойдет все тот же netcat.
На нашем проблемном сервере запускаем в отдельном терминале
Теперь все данные, которые попадут в pipe автоматически попадут на stdin в netcat, который их отправит в сеть на порт 7777.
Все что нам осталось сделать это начать писать наши данные в этот именованный pipe.
У нас уже есть запущенное приложение:
Из всех флагов нам нужен только O_WRONLY так как файл уже существует и очищать нам его не нужно
Данные идут, проверяем проблемный сервер
Данные сохранились, проблема решена.
Пользуясь случаем, передаю привет коллегам из компании Degiro.
Слушайте подкасты Радио-Т.
В качестве домашнего задания предлагаю подумать, что будет в файл дескрипторах процесса cat и sleep если запустить такую команду:
Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:
- PWN;
- криптография (Crypto);
- cетевые технологии (Network);
- реверс (Reverse Engineering);
- стеганография (Stegano);
- поиск и эксплуатация WEB-уязвимостей.
Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.
Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.
Закрытие дескрипторов файлов
Попытка обращения к закрытому дескриптору файла
Всё дело в том, что мы попытались обратиться к несуществующему дескриптору.
Будьте внимательны, закрывая дескрипторы файлов в сценариях. Если вы отправляли данные в файл, потом закрыли дескриптор, потом — открыли снова, оболочка заменит существующий файл новым. То есть всё то, что было записано в этот файл ранее, будет утеряно.
Решение задания fd
Нажимаем на первую иконку с подписью fd, и нам говорят, что нужно подключиться по SSH с паролем guest.
При подключении мы видим соотвтствующий баннер.
Давайте узнаем какие файлы есть на сервере, а также какие мы имеем права.
Таким образом мы можем можем прочитать исходный код программы, так как есть право читать для всех, и выполнить с правами владельца программу fd (установлен sticky-бит). Давай просмотрим исходный код.
Из кода следует, что программа принимает в качестве параметра число, отнимает от него 0x1234 и использует в качестве дескриптора для получения строки, которая должна быть равна «LETMEWIN».
Таким образом нам нужно послать программе строку «LETMEWIN» через стандартный поток ввода (stdin). Для этого дескриптор, который передается в функцию read(), должен быть равен 0. То есть в качестве параметра программы нужно использовать число 0х1234. Переведем его в десятичный вид.
Теперь запустим программу с параметром 4660, отпавим нужную строку и заберем флаг.
Как результат, получаем первое очко.
Вот с такого легкого задания, благодаря которому нужно было разобраться с дескрипторами, начинается pwnable.kr. До встречи в следующих статьях!
В прошлый раз, в третьей части этой серии материалов по bash-скриптам, мы говорили о параметрах командной строки и ключах. Наша сегодняшняя тема — ввод, вывод, и всё, что с этим связано.
Вы уже знакомы с двумя методами работы с тем, что выводят сценарии командной строки:
- Отображение выводимых данных на экране.
- Перенаправление вывода в файл.
Тузик
В начале моей карьеры я пытался создать небольшое приложение, в котором нужно было хранить информацию о пользователях. И тогда я думал, а как мне сопоставить пользователя к его данным. Есть, например, у меня Иванов Иван Иваныч, и есть у него какие-то данные, но как их подружить? Я могу указать напрямую, что собака по имени «Тузик» принадлежит этому самому Ивану. Но что, если он сменит имя и вместо Ивана станет, например, Олей? Тогда получится, что наша Оля Ивановна Иванова больше не будет иметь собаки, а наш Тузик все еще будет принадлежать несуществующему Ивану. Решить эту проблему помогла база данных, которая каждому пользователю давала уникальный идентификатор (ID), и мой Тузик привязывался к этому ID, который, по сути, был просто порядковым номером. Таким образом хозяин у тузика был с ID под номером 2, и на какой-то момент времени под этим ID был Иван, а потом под этим же ID стала Оля. Проблема человечества и животноводства была практически решена.
Redirect и Pipe
Вы можете легко переопределить эти 3 файл дескриптора в любом процессе, в том числе и в bash, например через трубу(pipe), соединяющую два процесса, смотрим
Вы можете сами запустить эту команду с strace -f и увидеть, что происходит внутри, но я вкратце расскажу.
Наш родительский процесс bash с PID 15771 парсит нашу команду и понимает сколько именно команд мы хотим запустить, в нашем случае их две: cat и sleep. Bash знает что ему нужно создать два дочерних процесса, и объединить их одной трубой. Итого bash потребуется 2 дочерних процесса и один pipe.
Перед созданием дочерних процессов bash запускает системный вызов pipe и получает новые файл дескрипторы на временный буфер pipe, но этот буфер никак пока не связывает наши два дочерних процесса.
Для родительского процесса это выглядит так будто pipe уже есть, а дочерних процессов еще нет:
Затем с помощью системного вызова clone bash создает два дочерних процесса, и наши три процесса будут выглядеть так:
Не забываем, что 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. В нашем случае после запуска исполняемых файлов все текущие файл дескрипторы сохранятся.
Проверяем в консоли:
Как видите уникальный номер нашего pipe у нас в обоих процессах совпадает. Таким образом у нас есть связь между двумя разными процессами с одним родителем.
Для тех, кто не знаком с системными вызовами, которые использует bash, крайне рекомендую запустить команды через strace и посмотреть, что происходит внутри, например, так:
Вернемся к нашей проблеме с нехваткой места на диске и попыткой сохранить данные без перезапуска процесса. Напишем небольшую программу, которая будет записывать на диск примерно 1 мегабайт в секунду. При этом если по какой-либо причине мы не смогли записать данные на диск, мы будем просто игнорировать это и пытаться записать данные вновь через секунду. В примере я использую Python, вы можете использовать любой другой язык программирования.
Запустим программу и посмотрим на файл дескрипторы
Как видим у нас есть наши 3 стандартные файл дескрипторы и еще один, который мы открыли. Проверим размер файла:
данные пишутся, пробуем поменять права на файл:
Видим, что данные все еще пишутся, хотя наш пользователь не имеет права писать в файл. Попробуем его удалить:
Куда пишутся данные? И пишутся ли вообще? Проверяем:
Да, наш файл дескриптор все еще существует, и мы можем работать с этим файл дескриптором как с нашим старым файлом, мы можем его читать, очищать и копировать.
Смотрим на размер файла:
Размер файла 19923457. Пробуем очистить файл:
Как видим размер файла только увеличивается и наш транкейт не сработал. Обратимся к документации по системному вызову open. Если при открытии файла мы используем флаг O_APPEND, то при каждой записи операционная система проверяет размер файла и пишет данные в самый конец файла, причем делает это атомарно. Это позволяет нескольким тредам или процессам писать в один и тот же файл. Но в нашем коде мы не используем этот флаг. Мы можем увидеть другой размер файла в lsof после транкейт только если откроем файл для дозаписи, а значит в нашем коде вместо
мы должны поставить
Проверяем с «w» флагом
Итоги
Сегодня вы узнали о том, как в сценариях командной строки работают ввод и вывод. Теперь вы умеете обращаться с дескрипторами файлов, создавать, просматривать и закрывать их, знаете о перенаправлении потоков ввода, вывода и ошибок. Всё это очень важно в деле разработки bash-скриптов.
В следующий раз поговорим о сигналах Linux, о том, как обрабатывать их в сценариях, о запуске заданий по расписанию и о фоновых задачах.
Перенаправление ввода в скриптах
Для перенаправления ввода можно воспользоваться той же методикой, которую мы применяли для перенаправления вывода. Например, команда exec позволяет сделать источником данных для STDIN какой-нибудь файл:
Эта команда указывает оболочке на то, что источником вводимых данных должен стать файл myfile , а не обычный STDIN . Посмотрим на перенаправление ввода в действии:
Вот что появится на экране после запуска скрипта.
Перенаправление ввода
Некоторые администраторы Linux используют этот подход для чтения и последующей обработки лог-файлов.
Программируем уже запущенный процесс
Часто программисты при создании и тестировании программы используют дебагеры (например GDB) или различные уровни логирования в приложении. Linux предоставляет возможность фактически писать и менять уже запущенную программу, например менять значения переменных, устанавливать breakpoint и тд и тп.
Возвращаясь к оригинальному вопросу с нехваткой места на диске для записи файла, попробуем сэмулировать проблему.
Создадим файл для нашего раздела, который мы подмонтируем как отдельный диск:
Создадим файловую систему:
Подмонтируем файловую систему:
Создаем директорию с нашим владельцем:
Откроем файл только на запись в нашей программе:
Ждем несколько секунд
Итак, мы получили проблему, описанную в начале этой статьи. Свободного места 0, занятого 100%.
Мы помним, что по условиям задачи мы пытаемся записать очень важные данные, которые нельзя потерять. И при этом нам нужно починить сервис без перезапуска процесса.
Допустим, у нас все же есть место на диске, но в другом разделе, например в /home.
Попробуем «перепрограммировать на лету» наш код.
Смотрим PID нашего процесса, который съел все место на диске:
Подключаемся к процессу через gdb
Смотрим открытые файл дескрипторы:
Смотрим информацию о файл дескрипторе с номером 3, который нас интересует
Помня о том, какой системный вызов делает Python (смотрите выше, где мы запускали strace и находили вызов open), обрабатывая наш код для открытия файла, мы делаем то же самое самостоятельно от имени нашего процесса, но биты O_WRONLY|O_CREAT|O_TRUNC нам нужно заменить на числовое значение. Для этого открываем исходники ядра, например тут и смотрим какие флаги за что отвечают
Объединяем все значения в одно, получаем 00001101
Запускаем наш вызов из gdb
Итак мы получили новый файл дескриптор с номером 4 и новый открытый файл на другом разделе, проверяем:
Мы помним пример с pipe — как bash меняет файл дескрипторы, и уже выучили системный вызов dup2.
Пробуем подменить один файл дескриптор другим
Закрываем файл дескриптор 4, так как нам он не нужен:
И выходим из gdb
Проверяем новый файл:
Как видим, данные пишутся в новый файл, проверяем старый:
Данные не потеряны, приложение работает, логи пишутся в новое место.
STDOUT
Итак, у нас есть некий файл с данными, к которому мы можем добавить другие данные с помощью этой команды:
То, что выведет pwd , будет добавлено к файлу myfile , при этом уже имеющиеся в нём данные никуда не денутся.
Перенаправление вывода команды в файл
Попытка обращения к несуществующему файлу
▍Перенаправление потока ошибок
▍Перенаправление потоков ошибок и вывода
Перенаправление ошибок и стандартного вывода
Перенаправление STDERR и STDOUT в один и тот же файл
После выполнения команды то, что предназначено для STDERR и STDOUT , оказывается в файле content .
STDIN
STDIN — это стандартный поток ввода оболочки. Для терминала стандартный ввод — это клавиатура. Когда в сценариях используют символ перенаправления ввода — < , Linux заменяет дескриптор файла стандартного ввода на тот, который указан в команде. Система читает файл и обрабатывает данные так, будто они введены с клавиатуры.
Многие команды bash принимают ввод из STDIN , если в командной строке не указан файл, из которого надо брать данные. Например, это справедливо для команды cat .
Когда вы вводите команду cat в командной строке, не задавая параметров, она принимает ввод из STDIN . После того, как вы вводите очередную строку, cat просто выводит её на экран.
Файл дескриптор
Проблема файла и программы, работающей с этим файлом, примерно такая же как нашей собаки и человека. Предположим я открыл файл под именем 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 и используется приложениями для вывода данных, сообщающих об ошибке
Список файл дескрипторов можно посмотреть у любого процесса, если вы знаете его PID.
Например, откроем консоль с bash и посмотрим PID нашего процесса
Во второй консоли запустим
Файл дескриптор с номером 255 можете смело игнорировать в рамках данной статьи, он был открыт для своих нужд уже самим bash, а не прилинкованной библиотекой.
Сейчас все 3 файл дескриптора связаны с устройством псевдотерминала /dev/pts, но мы все равно можем ими манипулировать, например запустим во второй консоли
И в первой консоли мы увидим
Перенаправление вывода в скриптах
Существует два метода перенаправления вывода в сценариях командной строки:
- Временное перенаправление, или перенаправление вывода одной строки.
- Постоянное перенаправление, или перенаправление всего вывода в скрипте либо в какой-то его части.
Читайте также: