by Jan Malakhovski
README, в главном бранче репозитория быть не должно.lsgrep.c#include <unistd.h>
#include <stdio.h>
int main() {
int pid=0;
int status;
int fds[2];
pipe(fds);
if (pid=fork()) {
// parent
dup2(fds[1], 1);
close(fds[0]);
close(fds[1]);
execl ("/bin/ls", "ls", NULL);
}
else {
// child
dup2(fds[0], 0);
close(fds[0]);
close(fds[1]);
execl ("/bin/grep", "grep", "c", NULL);
}
}lsgrep-real.c#include <unistd.h>
#include <stdio.h>
int main() {
int status;
int pgp=fork();
if (pgp == 0)
{
setpgid(0, 0);
int fds[2];
pipe(fds);
int lspid=fork();
if (lspid == 0) {
dup2(fds[1], 1);
close(fds[0]);
close(fds[1]);
sleep(100);
execl("/bin/ls", "ls", NULL);
_exit(255);
}
dup2(fds[0], 0);
close(fds[0]);
close(fds[1]);
sleep(100);
execl ("/bin/grep", "grep", "c", NULL);
_exit(255);
}
setpgid(pgp, pgp);
waitpid(pgp, &status, 0);
return 0;
}daemon.c#include <unistd.h>
#include <stdio.h>
int main() {
close(0);
close(1);
close(2);
if (!fork())
{
setsid();
sleep(100);
}
return 0;
}lsgrep-real-with-signals.c#include <unistd.h>
#include <stdio.h>
#include <signal.h>
int pgp = 0;
int lspid = 0;
void interrupt_handler(int foo) {
if (pgp)
kill(-pgp, SIGINT);
}
int main() {
int status;
signal(SIGINT, &interrupt_handler); // This is cruel
// use sigaction(2)
pgp=fork();
if (pgp == 0)
{
setpgid(0, 0);
int fds[2];
pipe(fds);
lspid=fork();
if (lspid == 0) {
dup2(fds[1], 1);
close(fds[0]);
close(fds[1]);
sleep(100);
execl("/bin/ls", "ls", NULL);
_exit(255);
}
dup2(fds[0], 0);
close(fds[0]);
close(fds[1]);
sleep(100);
execl ("/bin/grep", "grep", "c", NULL);
_exit(255);
}
setpgid(pgp, pgp);
waitpid(pgp, &status, 0);
return 0;
}Требуется реализовать аналог утилиты find, поддерживающий опции -type и -iname, при помощи рекурсивного обхода на чистом bash с использованием только встроенных команд и, может быть, утилиты grep. Следовать симлинкам не следует.
/bash/find.shtestdir с какой-нибудь иерархией внутри):#!/bin/bash
testwith() {
find testdir -type $1 -iname "$2" | sort > /tmp/hw2-result.orig
./bash/find.sh testdir -type $1 -iname "$2" | sort > /tmp/hw2-result.gens
if diff /tmp/hw2-result.orig /tmp/hw2-result.gens &> /dev/null ;
then
echo OK
else
echo "FAIL: $1 '$2'"
fi
rm /tmp/hw2-result.*
}
for t in d f ;
do
for iname in '*' '*.txt' 'txt.*' ;
do
testwith $t "$iname"
done
doneВ тестере могут быть баги, я его не запускал. Приведённый тестер “хорошо” работает только, если его запускают на “своей” машине. В противном случае рекомендуется прочитать man по mktemp(1).
Класть тестер и тестовую директорию в основной бранч репозитория не следует.
Требуется реализовать скрипт, представляющий собой мутабельную очередь для утилиты wget. Аргументами скрипта являются URLы. При запуске первый инстанс должен демонизироваться, а остальные запуски только добавлять этому демону задания в очередь.
/bash/wgetqueue.sh#!/bin/bash
shopt -s nullglob
QPATH=$HOME/.nyaqueue
mkdir -p "$QPATH"
mkdir -p "$QPATH/requests"
for a in "$@"
do
r=`mktemp --tmpdir="$QPATH/requests"`
echo "$a" > "$r"
done
if [[ ! -f "$QPATH/running" ]]; then
touch "$QPATH/running"
trap "rm '$QPATH/running'" 0
while [ 1 ]
do
for a in "$QPATH/requests"/*
do
url=`cat "$a"`
rm "$a"
wget -c "$url"
done
sleep 1
done
fiПо поводу демонизации в bash. В задании требуется:
Для выполнения последнего следует разобраться, что означает конструкция
Также следует ответить себе на вопрос “Почему в bash нельзя без trap?”
Требуется поговорить со мной, что-то написать, получить от 0 до 50 баллов.
Требуется реализовать мега-урезанную версию утилиты sed.
Требуется реализовать библиотеку для построчного чтения из файлового дескриптора при помощи лишь одного системного вызова read со следующим интерфесом:
/unsed/readlines.h// Структура, в которой прячется файловый дескриптор, буфер и хозяйственная
// информация.
struct RL;
// Принимает файловый дескриптор и максимальный размер строки, которую требуется
// обрабатывать и возвращает указатель на свежевыделенную структуру типа RL
// или NULL в случае ошибки.
RL* rl_open(int fd, size_t max_size);
// Возвращает max_size, указанный при создании rl.
size_t rl_max_size (RL *rl);
// Освобождает структуру rl. При этом следует закрыть и файловый дескриптор,
// спрятанный внутри. Возвращает $0$, если всё хорошо или $-1$ в случае ошибки.
// В последнем случае код ошибки должен возвращаться через errno.
int rl_close(RL *rl);
// Читает строку (включая символ перевода строки) размером не более
// $min(max_size + 1, buf_size)$ из файлового дескриптора спрятанного
// в rl в буфер buf.
// * В случае успеха записывает строку в buf (включая перевод строки) и возвращает
// длину записанных в buf данных. Частичный результат не допускается.
// * В случае конца ввода возвращает $0$.
// * В случае, если строка в файловом дескрипторе больше `max_size + 1`
// возвращает $-3$. Несколько последующих вызовов также могут возвращать $-3$
// (пропуск хвоста слишком длинной строки).
// * В случае, если длина строки на вводе меньше `max_size + 1`, но больше
`buf_size`, то возвращает $-2$. Строка при этом безвозвратно выбрасывается.
// * В остальных случаях возвращает $-1$, устанавливая errno в код произошедшей
// ошибки.
// Философские факты: бывают строки нулевой длины, все строки файла кроме
// последней всегда заканчиваются `\n`, последняя строка в файле никогда не
// заканчивается `\n`.
int rl_readline(RL *rl, char * buf, size_t buf_size);/unsed/readlines.c — реализация интерфейса /unsed/readlines.h./unsed/readlines-main.c — простая программа, читающая свой ввод построчно и выводящая строки размером меньше константы (передаётся в argv[1]) на стандартный вывод при помощи системного вызова write. Заметье, что write имеет право не записать всё, что его просили. Это надо корректно учитывать./unsed/Makefile — скрипт сборки readlines-main для утилиты make./unsed/readlines-main — результат сборки /unsed/readlines-main.c.На любом языке программирования реализовать тестер своей программы. Должен работать следующим образом:
n, ./unsed/readlines-main $n.\n длиной от до , завершая их символом \n.\n).123\n12
пауза в 5 секунд
345\n
вывод (для достаточно большого ) должен быть:
123\n
пауза в 5 секунд
12345\n
а не
пауза в 5 секунд
123\n12345\n
/unsed/tester/,/unsed/tester/tester.sh (очевидно, должна быть написано на bash, но может тривиально запускать что-то другое),Makefile (который может запускать систему сборки для вашего языка, если нужно, но запуск make должен давать возможность нормально запустить tester.sh).Превратите readlines в shared-библиотеку. В Makefile следует добавить цель all-shared, собирающую библиотеку и readlines-main.c в бинарник динамический слинкованный с ней.
Наконец, реализуйте урезанную версию утилиты sed. Требуется уметь поддерживать только команду s без флагов и с флагом g. Сохранение синтаксиса sed для групп в регулярных выражения необязательно.
Для работы с регулярными выражениями следует использовать библиотеку pcre, динамически линкуясь с ней (во всех целях сборки).
«Программа» (sed-скрипт) передаётся в качестве единственного аргумента unsed, ввод читается со stdin. Следует считать, что на ввод подаётся строка в UTF-8.
/unsed/unsed.c — исходники утилиты,/unsed/Makefile — скрипт сборки с целями (как минимум) all и all-shared, обе из которых собирают readlines-main и unsed./unsed/unsed — результат сборки,Пример запуска (синтаксис для групп может отличаться):
Требуется поговорить со мной, что-то написать, получить от 0 до 50 баллов.
Требуется реализовать вариант аллокатора Хоарда с тремя субаллокаторами:
k округлением вверх до k. Линейный. Выделять куски из бакетов, у каждого бакета свой spinlock (или сделать CAS очередь на освобождение).K. Тупо mmap и munmap без блокировок.Для начала можно считать, что k = 32, K = 64K, но это должно быть можно просто поменять. Настоятельно советую потестить то, что получается при разных параметрах.
При реализации можно использовать C++ и STL, но я советую реализовать шаблонные функции и структуры данных на чистом C без классов и не работать с эксепшонами.
В результате должна получаться разделяемыая библиотека, которую можно подсунуть LD_PRELOAD в любую программу.
Любой из трёх субаллокаторов должно быть можно без больших усилий отключить в коде редактированием одной только функции malloc.
Файлы в репозитории:
/myalloc/myalloc.c — тут должны быть определены malloc и free./myalloc/Makefile — скрипт сборки.Файлы, генерируемы скриптом сборки:
/myalloc/libmyalloc.so — библиотека.Дедлайн: 23:59:59 25 апреля 2013.
Требуется реализовать утилиту, принимающую 2 * n номеров файловых дескрипторов в argv и копирующую данные из дескриптора 2 * k - 1 в 2 * k для всех k, 1 < k <= n= с использованием poll(2) и epoll(2).
/copy-paster/cp-poll.c — исходник утилиты с использованием poll(2)./copy-paster/cp-epoll.c — исходник утилиты с использованием epoll(2)./copy-paster/tester.sh и (если нужно) /copy-paster/tester.c — система тестирования./copy-paster/tests/ (если нужно) — директория с тестами и/или файлами/данными на которых производится тестирование./copy-paster/Makefile — скрипт сборки.*.c и *.h файлы, если нужны./copy-paster/cp-poll — утилита с poll(2)./copy-paster/cp-epoll — утилита с epoll(2)./copy-paster/tester.sh должен принимать имя бинарника в качестве аргумента и тестировать его на профпригодность. В случае, если что-то не так, tester.sh должен завершаться с ненулевым кодом возврата. Внутри у tester.sh и (если есть) tester.c должно происходить что-то разумное, а не создание видимости тестирования. В частности, следует проверить что произойдёт в случае, если пишущий конец какого-то fd закроется потому, что пишущий процесс погиб.
Требуется поговорить со мной, что-то написать, получить от 0 до 50 баллов.
Смотрите список рассылки. Альтернативно, если вы сдали все предыдущие работы вовремя, то можно попросить и получить интересное персональное задание за бонусные баллы.
Требуется поговорить со мной, что-то написать, получить от 0 до 50 баллов.