
- •Системное программирование в 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.10. Управление терминалом
Упражнение 13.61. Напишите функции включения и выключения режима эхо-отображения набираемых на клавиатуре символов.
uses linux,crt;
const ECHO=8;
var
t:termios;
s,ms:string;
c:char;
begin
writeln('Для включения эхо введите on, для выключения эхо введите off');
readln(s);
tcgetattr(0,t);
writeln(t.c_lflag);
if s='on' then
begin
t.c_lflag:=t.c_lflag or ECHO;
end;
if s='off' then
begin
t.c_lflag:=t.c_lflag and not ECHO;
end;
tcsetattr(0,tcsanow,t);
readln(ms);
writeln(ms);
end.
13.11. Дата и время
Упражнение 13.62. Составьте аналог команды date.
ses crt,dos;
var y,h,d,dw,ch,m,s,ms:word;
BEGIN
getdate(y,h,d,dw);
case dw of
1:write('Пн');
2:write('Вт');
3:write('Ср');
4:write('Чт');
5:write('Пт');
6:write('Сбт');
7:write('Вс');
end;
write(' ');
case h of
1:write('Янв');
2:write('Фев');
3:write('Мар');
4:write('Апр');
5:write('Май');
6:write('Июн');
7:write('Июл');
8:write('Авг');
9:write('Сен');
10:write('Окт');
11:write('Ноя');
12:write('Дек');
end;
write(' ');
write(d,' ');
gettime(ch,m,s,ms);
write(ch,':',m,':',s,':',ms,' ',y);
readln;
END.
Упражнение 13.63. Составьте аналог команды cal.
uses crt,dos;
procedure cl(year,mes,pol_1:word);
var arr:array [0..7,1..7] of string[2];
i,j,kdm,n:byte;
v:boolean;
kd,k:word;
s:string[2];
begin
v:=false;
for i:=0 to 7 do
for j:=1 to 7 do
arr[i,j]:=' ';
if ((year mod 4=0)and(year mod 100<>0))or((year mod 4=0)and(year mod 100=0)and(year mod 400=0))
then v:=true
else if (year mod 100=0)and(year mod 400<>0)then v:=false;
case mes of
1:begin writeln('Янв');
kdm:=31;
kd:=0;
end;
2:begin writeln('Фев');
kd:=31;
if v then kdm:=29 else kdm:=28;
end;
3:begin writeln('Мар');
kdm:=31;
if v then kd:=60 else kd:=59;
end;
4:begin writeln('Апр');
kdm:=30;
if v then kd:=91 else kd:=90;
end;
5:begin writeln('Май');
kdm:=31;
if v then kd:=121 else kd:=120;
end;
6:begin writeln('Июн');
kdm:=30;
if v then kd:=152 else kd:=151;
end;
7:begin writeln('Июл');
kdm:=31;
if v then kd:=182 else kd:=181;
end;
8:begin writeln('Авг');
kdm:=31;
if v then kd:=213 else kd:=212;
end;
9:begin writeln('Сен');
kdm:=30;
if v then kd:=244 else kd:=243;
end;
10:begin writeln('Окт');
kdm:=31;
if v then kd:=274 else kd:=273;
end;
11:begin writeln('Ноя');
kdm:=30;
if v then kd:=305 else kd:=304;
end;
12:begin writeln('Дек');
kdm:=31;
if v then kd:=335 else kd:=334;
end;
end;
arr[0,1]:='ПН';
arr[0,2]:='ВТ';
arr[0,3]:='СР';
arr[0,4]:='ЧТ';
arr[0,5]:='ПТ';
arr[0,6]:='СБ';
arr[0,7]:='ВС';
pol_1:=(pol_1+kd) mod 7;
k:=pol_1+1;
n:=1;
for j:=k to 7 do
begin
str(n,s);
arr[1,j]:=s;
n:=n+1;
end;
for i:=2 to 7 do
for j:=1 to 7 do
begin
if n<=kdm then begin //n:=n+1;
str(n,s);
n:=n+1;
end
else s:=' ';
arr[i,j]:=s;
end;
for i:=0 to 7 do
begin
for j:=1 to 7 do
write(arr[i,j]:2,' ');
writeln;
end;
end;
var
y,m,mm,d,dw:word;
kvy,kd:longint;
err:integer;
ii,jj,x1,x2,y1,y2:byte;
begin
m:=0;
if paramcount=0 then getdate(y,m,d,dw);
if paramcount=1 then val(paramstr(1),y,err);
if paramcount=2 then begin
val(paramstr(1),y,err);
val(paramstr(2),m,err);
end;
if err<>0 then begin
writeln('error');
exit;
end;
kvy:=((y-1) div 4)-((y-1) div 100)+((y-1) div 400);
kd:=365*(y-1-kvy)+366*kvy;{kol dney do jen year}
dw:=kd mod 7;
gotoxy(1,1);
mm:=0;
y1:=1;
if m=0 then for ii:=0 to 2 do
begin
y2:=y1+10;
x1:=1;
for jj:=0 to 3 do
begin
x2:=x1+20;
mm:=mm+1;
window(x1,y1,x2,y2);
cl(y,mm,dw);
x1:=x1+24;
end;
y1:=y1+10;
end;
if (m>0)and (m<=12) then cl(y,m,dw);
if y<0 then exit;
window(1,31,25,32);
writeln;
end.
Упражнение 13.64. Напишите функцию, переводящую год, месяц, день, часы, минуты и секунды в число секунд, прошедшее до указанного момента с 00 часов 00 минут 00 секунд 1 Января 1970 года.
uses sysutils;
var
s1,s2,s3,s4,s5,s6:integer;
rezult:real;
function kol_days_y(y,m,d:integer):longint;
var i,god,sum:integer;
begin
sum:=0;
{Подсчет дней при прошедших годах}
god:=1970;
repeat
if y=god then begin break;end;
if (god mod 400<>0)and((god mod 4) =0)and((god mod 100)<>0)then sum:=sum+366 else
sum:=sum+365;
god:=god+1;
until god>y;
{Подсчет дней при определенном количестве месяцев}
god:=1;
repeat
if god=m then begin break;end;
case god of
1,3,5,7,8,10,12:begin sum:=sum+31;end;
4,6,9,11:sum:=sum+30;
2:begin
if ((y mod 4) =0)and((y mod 100)<>0)then sum:=sum+29 else
sum:=sum+28;
end;
end;
god:=god+1;
until god>m;
kol_days_y:=sum+d-1;{Начало дней не с нуля, поэтому и -1}
end;
begin
if paramcount<>6 then
begin
writeln('Введите правильно дату и время. Например: 2004 2 20 12 45 55');
halt(1);
end else
begin
s1:=strtoint(paramstr(1));
s2:=strtoint(paramstr(2));
s3:=strtoint(paramstr(3));
s4:=strtoint(paramstr(4));
s5:=strtoint(paramstr(5));
s6:=strtoint(paramstr(6));
if (s1<0)or(s2<0)or(s3<0)or(s4<0)or(s5<0)or(s6<0)then
begin
writeln('Введите положительные значения');
halt(1);
end;
if (s2<1)or(s2>12)then
begin
writeln('Введите существующий месяц');
halt(1);
end;
if (s3<1)or(s3>31)then
begin
writeln('Введите существующий день');
halt(1);
end;
if (s4<0)or(s4>23)then
begin
writeln('Введите существующее количество часов');
halt(1);
end;
if (s5<0)or(s5>59)then
begin
writeln('Введите существующее количество минут');
halt(1);
end;
if (s6<0)or(s6>59)then
begin
writeln('Введите существующее количество секунд');
halt(1);
end;
end;
case s2 of
2:begin
if ((s1 mod 4)=0)and((s1 mod 4)=0)then
begin
if s3>29 then begin
writeln('В высокосном году в феврале не более 29 дней');
halt(1);
end;
end
else
if s3>28 then
begin
writeln('В феврале в невысокосном году не более 28 дней');
halt(1);
end;
end;
4,6,9,11: if s3>30 then
begin
writeln('В ',s2,' месяце не может быть больше 30 дней');
halt(1);
end;
end;
if s1<=1969 then
begin
writeln('Время назад не идет');
halt(1);
end;
writeln('Количество секунд прошедшее до указаного момента = ');
writeln(' = ',kol_days_y(s1,s2,s3)*24*3600+s4*3600+s5*60+s6,'c.');
end.
Упражнение 13.65. Напишите "часы", выдающие текущее время каждые 3 секунды.
uses dos,crt,sysutils,linux;
var
Hour , Min , Sec , HSec : word ;
procedure handler(sig:longint);cdecl;
begin
end;
procedure sleep(count:integer);
var
old:signalhandler;
begin
old:=signal(SIGALRM,@handler);
alarm(count);
pause;
signal(SIGALRM,old);
alarm(0);
end;
function L0 (w : word ) : string;
var
s : string;
begin
Str( w , s );
if w<10 then
L0 := '0'+ s
else
L0 := s ;
end ;
var
s:string;
i:integer;
begin
WriteLn ( 'По системным часам, через каждые 3 секунды') ;
repeat
GetTime ( Hour , Min , Sec , HSec ) ;
s := L0 (Hour ) + ' : ' + L0 ( Min ) + ' : ' + L0 ( Sec ) ;
write(s);
sleep(3);
for i:=1 to length(s) do
write(#8);
until keypressed;
end.