- •Системное программирование в unix средствами Free Pascal
- •Глава 1. Основные понятия и терминология 13
- •Глава 2. Файл 17
- •Глава 3. Работа с файлами 43
- •Глава 4. Каталоги, файловые системы и специальные файлы 62
- •Глава 5. Процесс 86
- •Глава 6. Сигналы и их обработка 117
- •Глава 7. Межпроцессное взаимодействие при помощи программных каналов 139
- •Глава 8. Дополнительные методы межпроцессного взаимодействия 163
- •Глава 9. Терминал 196
- •Глава 10.Сокеты 224
- •Глава 11. Стандартная библиотека ввода/вывода 239
- •Глава 12. Разные дополнительные системные вызовы и библиотечные процедуры 267
- •Глава 13. Задачи с решениями 287
- •Предисловие о книге
- •Назначение этой книги
- •Спецификация х/Open
- •Структура книги
- •Что вы должны знать
- •Соглашения
- •Глава 1. Основные понятия и терминология
- •1.1. Файл
- •1.1.1. Каталоги и пути
- •1.1.2. Владелец файла и права доступа
- •1.1.3. Обобщение концепции файла
- •1.2. Процесс
- •1.2.1. Межпроцессное взаимодействие
- •1.3. Системные вызовы и библиотечные подпрограммы
- •Глава 2. Файл
- •2.1. Примитивы доступа к файлам в системе unix
- •2.1.1. Введение
- •2.1.2. Системный вызовfdopen
- •Описание
- •Предостережение
- •2.1.3. Создание файла при помощи вызоваfdopen
- •Описание
- •2.1.4. Системный вызов fdcreat
- •Описание
- •2.1.5. Системный вызовfdclose
- •Описание
- •2.1.6. Системный вызовfdread
- •Описание
- •Указатель чтения-записи
- •2.1.7. Системный вызовfdwrite
- •Описание
- •2.1.8. Пример copyfile
- •2.1.9. Эффективность вызововfdread иfdwrite
- •Описание
- •2.1.10. Вызов fdseek и произвольный доступ
- •Описание
- •2.1.11. Пример: гостиница
- •2.1.12. Дописывание данных в конец файла
- •2.1.13. Удаление файла
- •Описание
- •2.1.14. Системный вызов fcntl
- •Описание
- •2.2. Стандартный ввод, стандартный вывод и стандартный вывод диагностики
- •2.2.1. Основные понятия
- •2.2.2. Программа io
- •2.2.3. Использование стандартного вывода диагностики
- •2.3. Стандартная библиотека ввода/вывода: взгляд в будущее
- •Описание
- •Вывод сообщений об ошибках при помощи функции writeln
- •2.4. Системные вызовы и переменнаяlinuxerror
- •2.4.7. Подпрограмма perror
- •Глава 3. Работа с файлами
- •3.1. Файлы в многопользовательской среде
- •3.1.1. Пользователи и права доступа
- •Действующие идентификаторы пользователей и групп
- •3.1.2. Права доступа и режимы файлов
- •Описание
- •3.1.3. Дополнительные права доступа для исполняемых файлов
- •3.1.4. Маска создания файла и системный вызов umask
- •Описание
- •3.1.5. Вызовfdopen и права доступа к файлу
- •3.1.6. Определение доступности файла при помощи вызова access
- •Описание
- •3.1.7. Изменение прав доступа при помощи вызова chmod Описание
- •3.1.8. Изменение владельца при помощи вызова chown
- •Описание
- •3.2. Файлы с несколькими именами
- •3.2.1. Системный вызов link Описание
- •3.2.2. Системный вызов unlink
- •3.2.3. Системный вызов frename
- •Описание
- •3.2.4. Символьные ссылки
- •Описание
- •Описание
- •3.2.5. Еще об именах файлов
- •Описание
- •3.3. Получение информации о файле: вызов fstat
- •Описание
- •Описание
- •3.3.1. Подробнее о вызове chmod
- •Глава 4. Каталоги, файловые системы и специальные файлы
- •4.1. Введение
- •4.2. Каталоги с точки зрения пользователя
- •Текущий рабочий каталог
- •4.3. Реализация каталогов
- •4.3.1. Снова о системных вызовах link и unlink
- •4.3.2. Точка и двойная точка
- •4.3.3. Права доступа к каталогам
- •4.4. Использование каталогов при программировании
- •4.4.1. Создание и удаление каталогов
- •Описание
- •Описание
- •4.4.2. Открытие и закрытие каталогов
- •Описание
- •Описание
- •4.4.3. Чтение каталогов: вызовы readdir и rewinddir
- •Описание
- •Описание
- •Второй пример: процедура find_entry
- •4.4.4. Текущий рабочий каталог
- •4.4.5. Смена рабочего каталога при помощи вызова chdir Описание
- •4.4.6. Определение имени текущего рабочего каталога
- •Описание
- •Описание
- •4.4.7. Обход дерева каталогов
- •Описание
- •Описание
- •4.5. Файловые системы unix
- •4.5.1. Кэширование: вызовы sync и fsync
- •Описание
- •4.6. Имена устройств unix
- •4.6.1. Файлы блочных и символьных устройств
- •4.6.2. Структураtstat
- •4.6.3. Информация о файловой системе
- •Описание
- •4.6.4. Ограничения файловой системы: процедуры pathconf и fpathconf
- •Описание
- •Глава 5. Процесс
- •5.1. Понятие процесса
- •5.2. Создание процессов
- •5.2.1. Системный вызов fork
- •Описание
- •Идентификатор процесса
- •5.3. Запуск новых программ при помощи вызова ехес
- •5.3.1. Семейство вызовов ехес
- •Описание
- •Вызовы execv, execlpи execvp
- •5.3.2. Доступ к аргументам, передаваемым при вызове exec
- •5.4. Совместное использование вызовов ехес и fork
- •Пример docommand
- •5.5. Наследование данных и дескрипторы файлов
- •5.5.1. Вызов fork,файлы и данные
- •5.5.2. Вызов ехес и открытые файлы
- •5.6. Завершение процессов при помощи системного вызова halt Описание
- •5.7. Синхронизация процессов
- •5.7.1. Системный вызов wait Описание
- •5.7.2. Ожидание завершения определенного потомка: вызов waitpid
- •Описание
- •5.8. Зомби-процессы и преждевременное завершение программы
- •5.9. Командный интерпретатор smallsh
- •5.10. Атрибуты процесса
- •5.10.1. Идентификатор процесса
- •5.10.2. Группы процессов и идентификаторы группы процессов
- •Описание
- •5.10.3. Изменение группы процесса
- •Описание
- •5.10.4. Сеансы и идентификатор сеанса
- •Описание
- •Описание
- •5.10.5. Переменные программного окружения
- •Описание
- •5.10.6. Текущий рабочий каталог
- •5.10.7. Текущий корневой каталог
- •Описание
- •5.10.8. Идентификаторы пользователя и группы
- •5.10.9. Ограничения на размер файла: вызов ulimit
- •Описание
- •5.10.10. Приоритеты процессов
- •Описание
- •Глава 6. Сигналы и их обработка
- •6.1. Введение
- •6.1.1. Имена сигналов
- •6.1.2. Нормальное и аварийное завершение
- •6.2. Обработка сигналов
- •6.2.1. Наборы сигналов
- •Описание
- •6.2.2. Задание обработчика сигналов: вызов sigaction
- •Описание
- •Пример 1: перехват сигнала sigint
- •Пример 2: игнорирование сигнала sigint
- •Пример 3: восстановление прежнего действия
- •Пример 4: аккуратный выход
- •6.2.3. Сигналы и системные вызовы
- •6.2.4. Процедуры sigsetjmpи siglongjmp
- •Описание
- •6.3. Блокирование сигналов
- •Описание
- •6.4. Посылка сигналов
- •6.4.1. Посылка сигналов другим процессам: вызов kill
- •Описание
- •6.4.2. Посылка сигналов самому процессу: вызовы sigraiseи alarm
- •Описание
- •Описание
- •6.4.3. Системный вызов pause
- •Описание
- •6.4.4. Системные вызовы sigpending и sigsuspend
- •Описание
- •Глава 7. Межпроцессное взаимодействие при помощи программных каналов
- •7.1. Каналы
- •7.1.1. Каналы на уровне команд
- •7.1.2. Использование каналов в программе
- •Описание
- •7.1.3. Размер канала
- •7.1.4. Закрытие каналов
- •7.1.5. Запись и чтение без блокирования
- •7.1.6. Использование системного вызова select для работы с несколькими каналами
- •Описание
- •Описание
- •Описание
- •7.1.7. Каналы и системный вызов ехес
- •7.2. Именованные каналы, или fifo
- •7.2.1. Программирование при помощи каналов fifo
- •Описание
- •Глава 8. Дополнительные методы межпроцессного взаимодействия
- •8.1. Введение
- •8.2. Блокировка записей
- •8.2.1. Мотивация
- •8.2.2. Блокировка записей при помощи вызова fcntl
- •Описание
- •Установка блокировки при помощи вызова fcntl
- •Снятие блокировки при помощи вызова fcntl
- •Задача об авиакомпании acme Airlines
- •Проверка блокировки
- •8.3. Дополнительные средства межпроцессного взаимодействия
- •8.3.1. Введение и основные понятия
- •Ключи средств межпроцессного взаимодействия
- •Описание
- •Операция get
- •Другие операции
- •Структуры данных статуса
- •8.3.2. Очереди сообщений
- •Описание
- •Работа с очередью сообщений: примитивы msgsndи msgrcv
- •Описание
- •Пример передачи сообщений: очередь с приоритетами
- •Программа etest
- •Программа stest
- •Системный вызов msgctl
- •Описание
- •8.3.3. Семафоры Семафор как теоретическая конструкция
- •Системный вызов semget Описание
- •Системный вызов semctl Описание
- •Операции над семафорами: вызов semop
- •Описание
- •Флаг sem_undo
- •Пример работы с семафорами
- •8.3.4. Разделяемая память
- •Системный вызов shmget
- •Описание
- •Операции с разделяемой памятью: вызовы shmat и shmdt
- •Описание
- •Системный вызов shmctl Описание
- •Пример работы с разделяемой памятью: программа shmcopy
- •8.3.5. Команды ipcsи ipcrm
- •Глава 9. Терминал
- •9.1. Введение
- •9.2. Терминал unix
- •9.2.1. Управляющий терминал
- •9.2.2. Передача данных
- •9.2.3. Эхо-отображение вводимых символов и опережающий ввод с клавиатуры
- •9.2.4. Канонический режим, редактирование строки и специальные символы
- •9.3. Взгляд с точки зрения программы
- •9.3.1. Системный вызовfdopen
- •9.3.2. Системный вызов fdread
- •9.3.3. Системный вызов fdwrite
- •9.3.4. Функции ttynameи isatty
- •Описание
- •9.3.5. Изменение свойств терминала: структура termios
- •Описание
- •Описание
- •Определение структуры termios
- •Массив с_сс
- •Поле c_cflag
- •Описание
- •Поле c_iflag
- •Поле c_oflag
- •Поле с_lflag
- •Описание
- •9.3.6. Параметры min и time
- •9.3.7. Другие системные вызовы для работы с терминалом
- •Описание
- •9.3.8. Сигнал разрыва соединения
- •9.4. Псевдотерминалы
- •9.5. Пример управления терминалом: программа tscript
- •Глава 10.Сокеты
- •10.1. Введение
- •10.2. Типы соединения
- •10.3. Адресация
- •10.3.1. Адресация Internet
- •Описание
- •10.3.2. Порты
- •10.4. Интерфейс сокетов
- •10.4.1. Создание сокета
- •Описание
- •10.5. Программирование в режиме tcp-соединения
- •10.5.1. Связывание
- •Описание
- •10.5.2. Включение приема tcp-соединений
- •Описание
- •10.5.3. Прием запроса на установку tcp-соединения
- •Описание
- •10.5.4. Подключение клиента
- •Описание
- •10.5.5. Пересылка данных
- •Описание
- •10.5.6. Закрытие tcp-соединения
- •10.6. Программирование в режиме пересылок udp-дейтаграмм
- •10.6.1. Прием и передача udp-сообщений
- •Описание
- •10.7. Различия между двумя моделями
- •Глава 11. Стандартная библиотека ввода/вывода
- •11.1. Введение
- •11.2. Структура tfile
- •11.3. Открытие и закрытие потоков: процедуры fopenи fclose Описание
- •Описание
- •11.4. Посимвольный ввод/вывод: процедуры getc и putc Описание
- •11.5. Возврат символов в поток: процедура ungetc Описание
- •11.6. Стандартный ввод, стандартный вывод и стандартный вывод диагностики
- •11.7. Стандартные процедуры опроса состояния
- •Описание
- •11.8. Построчный ввод и вывод
- •Описание
- •Описание
- •11.9. Ввод и вывод бинарных данных: процедуры freadи fwrite Описание
- •11.10. Произвольный доступ к файлу: процедуры fseek, rewindи ftell
- •Описание
- •11.11. Форматированный вывод: семейство процедур printf Описание
- •Задание ширины поля и точности
- •Комплексный пример
- •Специальные символы
- •Процедура sprintf
- •11.12. Форматированный ввод: семейство процедур scanf Описание
- •11.13. Запуск программ при помощи библиотек стандартного ввода/вывода
- •Описание
- •Описание
- •11.14. Вспомогательные процедуры
- •11.14.1. Процедуры freopen и fdopen Описание
- •11.14.2. Управление буфером: процедуры setbufи setvbuf Описание
- •Глава 12. Разные дополнительные системные вызовы и библиотечные процедуры
- •12.1. Введение
- •12.2. Управление динамическим распределением памяти
- •Описание
- •Описание
- •Описание
- •Пример использования функции malloc:связные списки
- •Вызовы brk и sbrk
- •12.3. Ввод/вывод с отображением в память и работа с памятью
- •Описание
- •Системные вызовы ттар и munmap
- •Описание
- •Описание
- •12.4. Время
- •Описание
- •Описание
- •12.5. Работа со строками и символами
- •12.5.1. Семейство процедур strings
- •Описание
- •12.5.2. Преобразование строк в числовые значения
- •Описание
- •12.5.3. Проверка и преобразование символов
- •12.6. Дополнительные средства
- •12.6.1. Дополнение о сокетах
- •12.6.2. Потоки управления
- •Описание
- •12.6.3. Расширения режима реального времени
- •12.6.4. Получение параметров локальной системы
- •12.6.5. Интернационализация
- •12.6.6. Математические функции
- •12.6.7. Работа с портами ввода вывода
- •Глава 13. Задачи с решениями
- •13.1. Введение
- •13.2. Обработка текста
- •13.3. Бинарные файлы
- •13.4. Каталоги
- •13.5. Файловые системы
- •13.6. Файловая системаproc
- •13.7. Управление файлами
- •13.8. Управление процессами
- •13.9. Программные каналы
- •13.10. Управление терминалом
- •13.11. Дата и время
- •13.12. Генератор лексических анализаторовlex
- •Приложение 1. Коды ошибок переменной linuxerror и связанные с ними сообщения Введение
- •Список кодов и сообщений об ошибках
- •Приложение 2. История unix
- •Основные стандарты
- •Ieee/posix
- •Приложение 3. Модульstdio
- •Приложение4. Замечания о компиляции воFree Pascal 2.0
- •Литература
13.7. Управление файлами
Упражнение 13.41. Составьте аналог команды rm.
uses linux,sysutils;
var
f:text;
d:boolean;
k:char;
s:string;
begin
writeln('введите имя файла, который нужно удалить');
readln(s);
assign(f,s);
if s='' then
begin
writeln('повторите попытку');
exit;
end;
writeln('подтвердите удаление файла Y/N');
readln(k);
if (k='Y') or (k='y') then
begin
d:=deletefile(s);
if d then
writeln('файл удален')
else
writeln('файл не удален');
end
else
writeln('файл не удален');
end.
Упражнение 13.42. Используя системный вызов fstat, напишите программу, определяющую тип файла: обычный файл, каталог, устройство, FIFO-файл.
uses linux,strings,sysutils;
function gettype(mode:integer):string;
begin
if S_ISREG(mode) then
gettype:='файл'
else
if S_ISDIR(mode) then
gettype:='каталог'
else
if S_ISCHR(mode) then
gettype:='байтоориентированное устройство'
else
if S_ISBLK(mode) then
gettype:='блочноориентированное устройство'
else
if S_ISFIFO(mode) then
gettype:='FIFO-файл'
else
gettype:='другое';
end;
var
st:stat;
name:array[0..255] of char;
begin
if paramcount = 0 then
name:='.'
else
name:=fexpand(paramstr(1));
if not fstat(pchar(name),st) then
writeln('Ошибка вызова stat для ',name)
else
write(gettype(st.mode));
end.
Упражнение 13.43. Составьте аналог команды chgrp.
Uses linux;
Var
UID,GID:Longint;
F:Text;
Code:Integer;
begin
Writeln('This will only work if you are root.');
if ParamCount<3 then
begin
Writeln('Error!!!');
Writeln('Format: ./task <Filename> <UID> <GID>');
Halt(1);
end;
val(Paramstr(2),UID,Code);
if Code<>0 then
begin
Writeln('Error!!!');
Writeln('Format: ./task <Filename> <UID> <GID>');
Halt(1);
end;
val(Paramstr(3),GID,Code);
if Code<>0 then
begin
Writeln('Error!!!');
Writeln('Format: ./task <Filename> <UID> <GID>');
Halt(1);
end;
if not Chown(ParamStr(1),UID,GID) then
if LinuxError=Sys_EPERM then
Writeln('You are not root!')
else
Writeln('Chmod failed with exit code: ',LinuxError)
else
Writeln('Changed owner successfully!');
end.
Упражнение 13.44. Составьте аналог команды mkdir.
Program Tabs;
begin
{$I-}
if ParamCount=1 then
begin
MkDir(ParamStr(1));
if IOResult <> 0 then Writeln('Cannot create directory')
else Writeln('New directory created');
end
else Writeln('Error');
end.
Упражнение 13.45. Составьте аналог команды chmod.
uses linux;
var
f,ch:string;
n,i:byte;
d:integer;
begin
if paramcount<>2 then
begin
writeln('Используйте: ',paramstr(0),' права_доступа файл/каталог');
exit;
end;
f:=paramstr(2);
ch:=paramstr(1);
n:=length(ch);
d:=0;
for i:=1 to n do
if not (ch[i] in ['0'..'7']) then
begin
writeln('Права доступа должны быть в восьмеричном формате');
exit;
end
else
d:=d*8+byte(ch[i])-byte('0');
if not chmod(f,d) then
writeln('Ошибка установки прав доступа ',ch,' для ',f);
end.
Упражнение 13.46. Составьте аналог команды chown.
uses linux,strings,sysutils,crt;
type
plong=^longint;
procedure perror(s:pchar);cdecl;external 'c';
function strchr(s:string;c:char):boolean;
var
i:integer;
begin
for i:=1 to length(s) do
if s[i]=c then
begin
strchr:=true;
exit;
end;
strchr:=false;
end;
procedure getall(w:string;name:string;var uid,gid:integer);
var ts,nam1,namb1,namb2:string;
tx:text;
d:integer;
f:boolean;
begin
assign(tx,w);
reset(tx);
f:=false;
while not EOF (tx) and not f do
begin
readln(tx,ts);
d:=pos(':',ts);
nam1:=copy(ts,1,d-1);
delete(ts,1,d+2);
d:=pos(':',ts);
namb1:=copy(ts,1,d-1);
delete(ts,1,d);
val(namb1,d);
uid:=d;
d:=pos(':',ts);
namb2:=copy(ts,1,d-1);
val(namb2,d);
gid:=d;
if nam1=name then
f:=true;
end;
if not f then
begin
uid:=-1;
gid:=-1;
end;
close(tx);
end;
var
username,groupname,fname:string;
uid,gid:integer;
posit,temp:integer;
begin
if paramcount<>2 then
begin
writeln('Используйте: ',paramstr(0),' владелец[:группа] файл');
exit;
end;
username:=paramstr(1);
fname:=paramstr(2);
posit:=0;
posit:=pos(':',username);
if posit<>0 then
begin
groupname:=copy(username,posit+1,length(username)-posit);
username[0]:=char(posit-1);
getall('/etc/passwd',username,uid,gid);
getall('/etc/group',groupname,gid,temp);
end
else
getall('/etc/passwd',username,uid,gid);
if (uid=-1) or (gid=-1) then
begin
writeln('Неверное имя владельца (группы)');
exit;
end;
if not chown(fname,uid,gid) then
perror('Ошибка вызова chown');
end.
Упражнение 13.47. Создайте программу chmodr, рекурсивно изменяющую права доступа для всех файлов каталога и вложенных в него подкаталогов. Имя каталога и права указываются в командной строке.
uses linux,strings,sysutils,crt;
function gettype(mode:integer):char;
begin
if S_ISREG(mode) then
gettype:='-'
else
if S_ISDIR(mode) then
gettype:='d'
else
if S_ISCHR(mode) then
gettype:='c'
else
if S_ISBLK(mode) then
gettype:='b'
else
if S_ISFIFO(mode) then
gettype:='p'
else
gettype:='l';
end;
function obhod(prava:integer;name:pchar):boolean;
var
flag:boolean;
d:PDIR;
el:pdirent;
st:stat;
res:integer;
polniypath:array [0..2000] of char;
ch:string;
n,i:byte;
begin
flag:=true;
d:=opendir(name);
if d=nil then
begin
writeln('Ошибка открытия каталога ',name);
exit;
end;
el:=readdir(d);
while el<>nil do
begin
polniypath:=name;
if strcomp(name,'/')=0 then
strcat(polniypath,el^.name)
else
begin
if name[strlen(name)-1]<>'/' then
strcat(polniypath,'/');
strcat(polniypath,el^.name);
end;
if not fstat(pchar(polniypath),st) then
writeln('Ошибка вызова stat для ',polniypath)
else
begin
//if not (gettype(st.mode) = 'd') then
if not chmod(pchar(polniypath),prava) then
writeln('Ошибка установки прав доступа ',prava,' для ',polniypath);
end;
el:=readdir(d);
end;
closedir(d);
d:=opendir(name);
el:=readdir(d);
while el<>nil do
begin
polniypath:=name;
if strcomp(name,'/')=0 then
strcat(polniypath,el^.name)
else
begin
if name[strlen(name)-1]<>'/' then
strcat(polniypath,'/');
strcat(polniypath,el^.name);
end;
if not fstat(pchar(polniypath),st) then
writeln('Ошибка вызова stat для ',polniypath)
else
begin
if (gettype(st.mode)='d') and
(strcomp(el^.name,'.')<>0) and
(strcomp(el^.name,'..')<>0) then
begin
writeln('Переход в каталог ',polniypath);
if not obhod(prava,polniypath) then
flag:=false;
end;
end;
el:=readdir(d);
end;
closedir(d);
if not flag then
writeln(' У каталога ',name, ' не удалось изменить права доступа ');
// writeln('Для каталога ',name, ' получен ',flag);
obhod:=flag;
end;
var
name:array [0..2000] of char;
prava,i:integer;
ch:string;
begin
if paramcount<>2 then
begin
writeln('Используйте: ',paramstr(0),' права_доступа файл/каталог');
exit;
end;
name:=paramstr(2);
ch:=paramstr(1);
prava:=0;
for i:=1 to length(ch) do
if not (ch[i] in ['0'..'7']) then
begin
writeln('Права доступа должны быть в восьмеричном формате');
exit;
end
else
prava:=prava*8+byte(ch[i])-byte('0');
obhod(prava,name);
end.
Упражнение 13.48. Напишите программу, совмещающая команды mv и cp (в зависимости от своего названия).
uses linux,sysutils;
var
b:byte;
s:string;
f1,f2:file of byte;
begin
s:=paramstr(0);
delete(s,1,length(s)-2);
if s='mv' then
begin
if paramcount<2 then
begin
writeln('Error: wrong arguments');
writeln('введите имя файла, который хотите переименовать и новое имя файла');
halt(1);
end;
Assign(F1,paramstr(1));
Assign(F2,paramstr(2));
if not frename(paramstr(1),paramstr(2)) then
begin
writeln('невозможно переименовать ');
halt(1);
end;
end
else
if s='cp' then
begin
if paramcount<2 then
begin
writeln('Error: wrong arguments');
writeln('format: cp <fileinp> <fileout>');
Halt(1);
end;
Assign(f1,paramstr(1));
Reset(f1);
Assign(f2,paramstr(2));
Rewrite(f2);
while not eof(f1)do
begin
read(f1,b);
write(f2,b);
end;
close(f1);
close(f2);
end
else
writeln('Переименуйте программу в mv / cp');
end.
Упражнение 13.49. Составьте аналог команды sync.
procedure sync;cdecl; external 'c';
begin
sync;
end.
Упражнение 13.50. Создайте программу, выводящую содержимое символической ссылки, а затем – целевого файла, на который она указывает.
uses linux;
var
name,temp:array [0..1023] of char;
kol,fd:integer;
begin
if paramcount<>1 then
begin
writeln('Используйте: ',paramstr(0),' имя_ссылки');
exit;
end;
temp:=paramstr(1);
kol:=readlink(temp,name,1023);
if kol=-1 then
begin
writeln('Ошибка чтения ссылки ',temp);
exit;
end;
name[kol]:=#0;
writeln('По ссылке ',paramstr(1), ' найден файл ',name);
fd:=fdopen(name,Open_RDONLY);
if fd=-1 then
begin
writeln('Ошибка открытия ',name);
exit;
end;
kol:=fdread(fd,name,1024);
while kol>0 do
begin
fdwrite(1,name,kol);
kol:=fdread(fd,name,1024);
end;
fdclose(fd);
end.