Квазиполезное
git
-репозиторий, в котором будет вестись работа над домашними заданиями. Зарегистрировать репозиторий можно по ссылке http://goo.gl/forms/RZl2klLfAp.make clean && make
. Если на этом этапе происходит ошибка, тесты не запускаются.Обзавестись какой-нибудь Unix-like системой.
Написать на языке C программу, печатающую "Hello, world!
" (с переводом строки в конце).
/hello_world/hello_world.c
/hello_world/Makefile
/hello_world/hello_world
man 3 printf
make
ничего не делаетmake clean
удаляет всё, что создал make
Необходимо реализовать примитивный вариант утилиты cat
, копирующий символы из stdin на stdout. Для реализации ввода-вывода нужно пользоваться системными вызовами read
и write
. Функциями из stdio.h
(printf
, getchar
, putchar
, ...) можно пользоваться только для вывода отладочной информации и/или сообщений об ошибках.
/cat/cat.c
/cat/Makefile
/cat/cat
man 2 read
man 2 write
./cat < cat.c > cat2.c && diff cat.c cat2.c && echo OK
curl neerc.ifmo.ru/~os/blob.bin | ./cat > blob.bin && curl neerc.ifmo.ru/~os/blob.bin > blob2.bin && diff blob.bin blob2.bin && echo OK
(осторожно, 2×5Mb)Необходимо реализовать скрипт для командной оболочки bash
, обходящий указанную директорию и выводящий список файлов, изменённых более недели назад и являющихся символьными ссылками, которые ссылаются на несуществующий файл. Директория, которую нужно обойти, указана первым аргументом командной строки.
Найденные файлы можно выводить в любом порядке. Пути до файлов можно выводить в любом корректном формате. Например, все следующие варианты допустимы и являются путями до одного и того же файла: a/b/c/d
, ./a//b/c/d
, a/../a/b/c/d
.
/badlinks/badlinks.sh
man 1 test
man 1 bash
Скрипт создаст директорию hw2-example
. Запуск ./badlinks.sh hw2-example
должен вывести:
$ ./badlinks.sh hw2-example
hw2-example/bad-old-link
hw2-example/nested/bad-old-link2
hw2-example/link-to-nested/bad-old-link2
Реализовать программу, в течение 10 секунд ожидающую SIGUSR1 или SIGUSR2 и печатающую информацию о полученном сигнале в формате "<имя сигнала> from <pid>
". Здесь <имя сигнала>
— SIGUSR1
или SIGUSR2
, а <pid>
— номер процесса, от которого пришёл сигнал. Если никакой сигнал не пришёл, вывести No signals were caught
. Если пришло несколько сигналов, вывести информацию только про какой-либо один из них.
/sigusr/sigusr.c
/sigusr/Makefile
/sigusr/sigusr
man 7 signal
man 2 sigaction
man 1 kill
man 2 kill
man 3 sleep
или man 2 alarm
signal(2)
— не тот системный вызов, который вы ищетеprintf
-а?$ ./sigusr > tmp & sleep 2; kill -SIGUSR1 $!; wait; cat tmp
SIGUSR1 from <pid>
$ ./sigusr
No signals were caught
Вам требуется написать упрощённую версию командного интерпретатора. Он будет считывать со стандартного ввода команду, выполнять её, дожидаться её завершения, и повторять сначала.
Команда --- это строка, заканчивающаяся символом перевода строки. Эту строку нужно разбить по символу "|
" на подкоманды. Каждую подкоманду нужно разбить по пробелу на имя и аргументы, и запустить. Стандартный вывод первой подкоманды нужно перенаправить на стандартный ввод второй, стандартный вывод второй --- на стандартный ввод третьей, ... Стандартный ввод для первой подкоманды совпадает со стандартным вводом командного интерпретатора, стандартный вывод последней --- со стандартным выводом интерпретатора.
Если ввод кончился, интерпретатор должен завершиться. Если интерпретатору прилетел SIGINT
(ctrl+C), то он должен быть перепослан запущенной команде.
Для наглядности, печатайте приглашение $
тогда, когда можно вводить команду.
/simplesh/simplesh.c
/simplesh/Makefile
/simplesh/simplesh
host$ ./simplesh
> $
< ls
> <содержимое директории>
> $
< cat /proc/cpuinfo | grep model | grep name | sed -re s/.*:\s(.*)/\1/ | uniq
> <модель процессора>
> $
< ^D
<
и >
символизируют ввод и вывод и показаны исключительно для наглядности.
host$ ./simplesh
> $
< cat | wc -l
< first line
< second line
< third line
< ^D
> 3
> $
< cat|wc -l
< first
< second
< third
< ^D
> 3
> $
< ^D
Запуск cat | sleep 1 | cat
должен вести себя так же, как при запуске в обычном шелле: точно так же реагировать на ввод, столько же работать и не плодить зомби-процессы. То же относится к sleep 15 | sleep 1 | sleep 15
.
Проверка того, что команда считывается правильно: (echo -ne l; sleep 1; echo s) | ./simplesh
(запускать в настоящем шелле, а не в реализуемом) должно показывать содержимое текущей директории.
Уметь объяснять, что происходит при запуске echo -ne "cat\nhello" | ./simplesh
и мотивировать, почему именно это - правильное поведение.
yes date | ./simplesh
должно выводить бесконечно много раз текущее время.
(echo md5sum; sleep 1; dd if=/dev/zero bs=1024 count=100000) | ./simplesh
должно печатать, среди прочего, 75a1e608e6f1c50758f4fee5a7d8e3d0
.
read
и write
.n
целиком, она должна быть прочитана с помощью одного вызова read
вместо n
вызовов./simplesh
своего репозитория.read
read
, читающий команду, может считать начало входных данных командыВам нужно написать существенно упрощённую версию демона sshd
. Программа слушает подключения по TCP на заданном порту. Для каждого подключившегося клиента она открывает новый псевдотерминал, в котором будет запущен /bin/sh
, и транслирует происходящее в нём клиенту. Программа должна демонизироваться и записывать свой pid в текстовом виде в файл /tmp/rshd.pid
. Обслуживание множества клиентов реализовать с помощью select
, poll
или epoll
.
Дополнителные процессы и/или потоки можно создавать только в целях демонизации и для запуска /bin/sh
. Для передачи данных между клиентом и его шеллом завести два буфера фиксированного размера: от клиента к шеллу и в обратную сторону.
Несложно заметить, что в задании используется много новых вещей, которые не использовались в предыдущих заданиях: сеть, мультиплексирование ввода-вывода, псевдотерминалы и демонизация. Далее небольшой план, следуя которому можно реализовать требуемое, используя одновременно не более одной новой вещи. Более того, некоторые маленькие примеры работы с poll
и с псевдотерминалами можно найти в шапке этого документа.
pipe
-ы. Задание превращается в следующее:
/bin/sh
;O_NONBLOCK
);O_NONBLOCK
на select
, poll
или epoll
;/rshd/rshd.c
/rshd/Makefile
rshd/rshd
man 2 socket
, man 2 bind
, man 2 listen
, man 2 accept
man 3 getaddrinfo
: там можно найти пример работы с сетьюman 2 select
, man 2 poll
, man 2 epoll_{create,ctl,wait}
man 3 posix_openpt
, man 3 grantpt
, man 3 unlockpt
, man 3 ptsname
./rshd 1234
.nc localhost 1234
. Должно появиться приглашение $
.^D
порожденный процесс sh
-потомок rshd
завершается и утилизируется (не висит как зомби).exit
внутри sh
-сессии (или при любом другом завершении шелла) не остается зомби.Запустить в удалённом шелле hexdump /dev/urandom
, увидеть, что он работает. Запустить его же во втором терминале, увидеть, что оба работают одновременно.
Запустить echo "hexdump /dev/urandom" | nc localhost 1234 | (sleep 1000000; cat)
, убедиться, что компьютер не завис наглухо.