подобно Fork, создает дочерний процесс,
uses linux;
TCloneFunc=function(args:pointer):longint;cdecl;
Clone(func:TCloneFunc;sp:pointer;flags:longint;args:pointer):longint;
Clone, подобно Fork, создает дочерний процесс, являющийся копией родительского. Однако, в отличие от Fork, процесс-потомок совместно с родителем использует некоторые части контекста, что делает его подходящим для реализации потоков: множества экземпляров программы, разделяющих общую память.
При создании потомка запускается функция Func, которой передаются параметры Args. Возвращаемым значением Func является код завершения потомка.
Указатель sp
хранит адрес памяти, зарезервированной под стек дочернего процесса.
Параметр Flags определяет поведение вызова Clone. Младший байт Flags содержит номер сигнала, который будет послан родителю при завершении потомка. Он может быть объединен с помощью побитового ИЛИ со следующими константами:
CLONE_VM Родитель и потомок разделяют память, включая отображенную вызовом mmap.
CLONE_FS Родитель и потомок разделяют параметры файловой системы; вызовы chroot, chdir и umask действуют на оба процесса.
CLONE_FILES Таблица дескрипторов файлов разделяется родителем и потомком.
CLONE_SIGHAND Таблица обработчиков сигналов разделяется родителем и потомком, однако маски сигналов различаются.
CLONE_PID Родитель и потомок имеют одинаковый pid.
Clone возвращает идентификатор потомка или -1 в случае ошибки, устанавливая значение linuxerror в Sys_EAGAIN (слишком много процессов) и Sys_ENOMEM (недостаточно памяти для создания дочернего процесса).
Пример использования Clone:
uses
Linux, Errors, crt;
const
Ready : Boolean = false;
aChar : Char = 'a';
function CloneProc( Arg: Pointer ): LongInt; Cdecl;
begin
WriteLn('Hello from the clone ',PChar(Arg));
repeat
Write(aChar);
Select(0,0,0,0,600);
until Ready;
WriteLn( 'Clone finished.');
CloneProc := 1;
end;
var
PID : LongInt;
procedure MainProc;
begin
а WriteLn(' cloned process PID: ', PID );
а WriteLn('Press <ESC> to kill ... ' );
а repeat
ааа Write('.');
ааа Select(0,0,0,0,300);
ааа if KeyPressed then
ааааа case ReadKey of
ааааааа #27: Ready := true;
ааааааа 'a': aChar := 'A';
ааааааа 'A': aChar := 'a';
ааааааа 'b': aChar := 'b';
ааааааа 'B': aChar := 'B';
ааааа end;
а until Ready;
а WriteLn('Ready.');
end;
const
а StackSze = 16384;
а theFlags = CLONE_VM+CLONE_FS+CLONE_FILES+CLONE_SIGHAND;
а aMsgаааа : PChar = 'Oops !';
var
а theStack : Pointer;
а ExitStat : LongInt;
begin
а GetMem(theStack,StackSze);
а PID := Clone(@CloneProc,
аааааааааааааа Pointer( LongInt(theStack)+StackSze),
ааааааааа аааааtheFlags,
аааааааааааааа aMsg);
а if PID < 0 then
ааа WriteLn('Error : ', LinuxError, ' when cloning.')
а else
ааа begin
ааа MainProc;
ааа case WaitPID(0,@ExitStat,Wait_Untraced or wait_clone) of
ааааа -1: WriteLn('error:',LinuxError,'; ',StrError(LinuxError));
аааааа 0: WriteLn('error:',LinuxError,'; ',StrError(LinuxError));
ааа else
ааааа WriteLn('Clone exited with: ',ExitStat shr 8);
ааа end;
ааа end;
а FreeMem( theStack, StackSze );
end.
Определение доступности файла при помощи вызова access
Системный вызов access определяет, может ли процесс получить доступ к файлу в соответствии с истинным (real), а не действующим (effective) идентификатором пользователя (и группы) процесса. Такой вызов позволяет процессу, получившему права при помощи бита STAT_ISUID, определить настоящие права пользователя, запустившего это процесс, что облегчает написание безопасных программ.
Определение имени текущего рабочего каталога
Спецификация XSI определяет функцию (а не системный вызов) getcwd, которая возвращает имя текущего рабочего каталога.
Определение структуры termios
Теперь изучим состав структуры termios. Определение структуры termios находится в файле linux и содержит следующие элементы:
termios = record
c_iflag, (* Режимы ввода *)
c_oflag, (* Режимы вывода *)
c_cflag, (* Управляющие режимы *)
c_lflag : Cardinal; (* Режимы дисциплины линии связи *)
c_line : char; (* Дисциплина линии связи *)
c_cc : array [0..NCCS-1] of char; (* Управляющие символы *)
end;
Проще всего рассматривать структуру, начав с ее последнего элемента с_сс.
Основные понятия
Система UNIX автоматически открывает три дескриптора файла для любой выполняющейся программы. Эти дескрипторы называются стандартным вводом (standard input), стандартным выводом (standard output) и стандартным выводом диагностики (standard error). Они всегда имеют значения 0, 1 и 2 соответственно. Недопустимо путать эти дескрипторы с похожими по названию стандартными потоками stdin, stdout и stderr из стандартной библиотеки ввода/ вывода.
По умолчанию вызов fdread для стандартного ввода приведет к чтению данных с клавиатуры. Аналогично запись в стандартный вывод или стандартный вывод диагностики приведет по умолчанию к выводу сообщения на экран терминала. Это первый пример использования примитивов доступа к файлам для ввода/вывода на устройства, отличные от обычных файлов.
Программа, применяющая эти стандартные дескрипторы файлов, тем не менее, не ограничена использованием терминала. Каждый из этих дескрипторов может быть независимо переназначен, если программа вызывается с использованием средств перенаправления, обеспечиваемых стандартным командным интерпретатором UNIX. Например, команда
$ prog_name < infile
приведет к тому, что при чтении из дескриптора со значением 0 программа будет получать данные из файла infile, а не с терминала, обычного источника для стандартного ввода.
Аналогично все данные, записываемые в стандартный вывод, могут быть перенаправлены в выходной файл, например:
$ prog_name > outfile
Возможно, наиболее полезно то, что можно связать стандартный вывод одной программы со стандартным вводом другой при помощи каналов UNIX. Следующая команда оболочки означает, что все данные, записываемые программой prog_1 в ее стандартный вывод, попадут на стандартный ввод программы prog_2 (такие команды называются конвейерами):
$ prog_1 | prog_2
Дескрипторы файлов стандартного ввода и вывода позволяют писать гибкие и совместимые программы. Программа может представлять собой инструмент, способный при необходимости принимать ввод от пользователя, из файла, или даже с выхода другой программы. Программа настроена на чтение из стандартного ввода, использует файловый дескриптор 0, а выбор входного источника данных откладывается до момента запуска программы.
Основные стандарты
В книге упомянуты следующие стандарты:
SVID
Название стандарта SVID является сокращением от AT&T System V Interface Definition (определение интерфейса ОС System V). Первоначально был разработан весной 1985 г. для описания интерфейса версии System V операционной системы UNIX. Стандарт SVID имеет ряд версий, последней из которых является третья редакция, вышедшая в 1989 г. Первое издание этой книги основывалось на стандарте SVID.
ANSI С
Комитет ANSI определяет стандарты различных информационных технологий. Наиболее интересным для системных программистов UNIX является стандарт языка ANSI С.
IEEE/POSIX
Институт электротехники и радиоэлектроники (Institute of Electrical and Electronics Engineers, сокращенно IEEE) разрабатывает в числе прочих стандарт интерфейса переносимой операционной системы (Portable Operating Systems Interface, сокращенно POSIX), который непосредственно базируется на ОС UNIX. Этот стандарт был впервые опубликован в 1988 г. и с тех пор несколько раз обновлялся. С темой данной книги наиболее тесно связаны следующие стандарты:
– стандарт IEEE 1003.1-1990, идентичный стандарту ISO POSIX-1 – ISO/IEC 9945-1, 1990, полное название которого: Information Technology – Portable Operating System Interface (POSIX) – Part 1: System Application Program Interface (API) [C language] (Информационные технологии – стандарт интерфейса переносимой операционной системы – часть 1. Системный интерфейс для прикладных программ [язык С]);
– стандарт IEEE 1003.2-1992, идентичный стандарту ISO POSIX-2 – ISO/IEC 9945-2, 1993, полное название которого: Information Technology – Portable Operating System Interface (POSIX) – Part 2: Shell and Utilities (Информационные технологии – стандарт интерфейса переносимой операционной системы – часть 2. Командный интерпретатор и утилиты).
Позже к стандарту были добавлены расширения и добавления, включая стандарты 1003.1b-1993, 1003.1с-1995, 1003.li-1995, охватывающие такие темы, как потоки управления и расширения реального времени.
Х/Open (в настоящее время Open Group)
Группа X/ Open Group объединила вышеупомянутые стандарты с другими; эти стандарты, вместе взятые, получили название спецификации Common Application Environment (общей среды приложений, сокращенно САЕ). Спецификация САЕ охватывает как системные, так и сетевые интерфейсы.
Текст книги лучше всего соответствует Issue 4 Version 2 X/Open САЕ Specification, System Interface and Headers (четвертому выпуску второй версии спецификации САЕ консорциума X/Open, системные интерфейсы и заголовки), вышедшей в августе 1994 г. Эта спецификация представляет собой базовый документ X/Open. Пятое издание спецификации САЕ, вышедшее в 1997 г., включает некоторые из недавно введенных в стандарт POSIX средств работы с потоками управления в режиме реального времени, а также других наработок из практики промышленного использования. Эти обновления также вошли в Version 2 of the Single UNIX Specification (вторую версию единой спецификации ОС UNIX) консорциума Open Group и в описание продукта UNIX98.
Открытие и закрытие каталогов
Для открытия каталога UNIX спецификация XSI определяет особую функцию opendir.
Ожидание завершения определенного потомка: вызов waitpid
Системный вызов wait позволяет родительскому процессу ожидать завершения любого дочернего процесса. Тем не менее, если нужна большая определенность, то можно использовать системный вызов waitpid для ожидания завершения определенного дочернего процесса.
Параметры MIN и TIME
Параметры MIN и TIME имеют значение только при выключенном флаге ICANON. Они предназначены для тонкой настройки управления вводом данных. Параметр MIN задает минимальное число символов, которое должен получить драйвер терминала для возврата из вызова fdread. Параметр TIME задает значение максимального интервала ожидания; этот параметр обеспечивает еще один уровень управления вводом с терминала. Время ожидания измеряется десятыми долями секунды.
Значения параметров MIN и МАХ находятся в массиве с_сс структуры termios, описывающей состояние терминала. Их индексы в массиве определяются постоянными VMIN и VTIME из файла stdio. Следующий фрагмент программы показывает, как можно задать их значения:
uses stdio, linux;
var
tdes:termios;
ttyfd:longint;
(* Получает текущее состояние *)
tcgetattr(ttyfd, tdes);
tdes.c_lflag := tdes.c_lflag and (not ICANON); (* Отключает канонический режим *)
tdes.c_cc[VMIN] := 64; (* В символах *)
tdes.c_cc[VTIME] := 2; (* В десятых долях секунды *)
tcsetattr(0, TCSAFLUSH, &tdes);
Константы VMIN и VTIME обычно имеют те же самые значения, что и постоянные VEOF и VEOL. Это означает, что параметры MIN и TIME занимают то же положение, что и символы eof и еоl. Следовательно, при переключении из канонического в неканонический режим нужно обязательно задавать значения параметров MIN и TIME, иначе может наблюдаться странное поведение терминала. (В частности, если символу eof
соответствует комбинация клавиш Ctrl+D,
то программа будет читать ввод блоками по четыре символа.) Аналогичная опасность возникает при возврате в канонический режим.
Существуют четыре возможных комбинации параметров MIN и TIME:
– оба параметра MIN и TIME равны нулю. При этом возврат из вызова fdread обычно происходит немедленно. Если в очереди ввода терминала присутствуют символы (напомним, что попытка ввода может быть осуществлена в любой момент времени), то они будут помещены в буфер процесса. Поэтому, если программа переводит свой управляющий терминал в режим прямого доступа при помощи сброса флага ICANON и оба параметра MIN и TIME равны нулю, то вызов
nread := fdread(0, buffer, SOMESZ);
вернет произвольное число символов от нуля до SOMESZ в зависимости от того, сколько символов находится в очереди в момент выполнения вызова;
– параметр MIN больше нуля, а параметр TIME равен нулю. В этом случае таймер не используется. Вызов fdread завершится только после того, как будут считаны MIN символов. Это происходит даже в том случае, если вызов read запрашивал меньше, чем MIN символов.
В самом простом варианте параметр MIN равен единице, а параметр TIME – нулю, что приводит к возврату из вызова fdread после получения каждого символа из линии терминала. Это может быть полезно при чтении с клавиатуры терминала, хотя могут возникнуть проблемы с клавишами, посылающими последовательности из нескольких символов;
– параметр MIN равен нулю, а параметр TIME больше нуля. В этом случае параметр MIN не используется. Таймер запускается сразу же после выполнения вызова fdread. Возврат из вызова read происходит, как только вводится первый символ. Если заданный интервал времени истекает (то есть проход время, заданное в параметре TIME в десятых долях секунды), то вызов read возвращает нулевые символы;
– оба параметра MIN и TIME больше нуля. Это, возможно, наиболее полезный и гибкий вариант. Таймер запускается после получения первого символа, а не при входе в вызов fdread. Если MIN символов будут получены до истечения заданного интервала времени, то происходит возврат из вызова fdread. Если таймер срабатывает раньше, то в программу пользователя возвращаются только символы, находящиеся при этом в очереди ввода. Этот режим работы полезен при поступлении ввода пакетами, которые посылаются в течение коротких интервалов времени. При этом упрощается программирование и уменьшается число необходимых системных вызовов. Такой режим также полезен, например, при работе с функциональными клавишами, которые посылают при нажатии на них сразу несколько символов.
Передача данных
Основной задачей драйвера терминала является передача данных между процессом и его терминальным устройством. На самом деле это достаточно сложное требование, так как пользователь может печатать символы в любое время, даже во время вывода. Чтобы лучше понять эту ситуацию, вернемся к рис. 9.1 и представим, что по путям от (С) к (В) и от (В) к (D) одновременно передаются данные. Напомним, что программа, представленная на схеме узлом (А), может выполнять только последовательные вызовы fdread или fdwrite.
Поскольку в каждый момент времени программа может обрабатывать только один поток данных терминала, то для одновременного управления двумя потоками дисциплина линии связи запоминает входные и выходные данные во внутренних буферах. Входные данные передаются программе пользователя, когда он выполняет вызов fdread. Входные символы могут быть потеряны при переполнении поддерживаемых ядром буферов или если число символов, поступивших на терминал, превысит ограничение MAX_INPUT, определенное в файле stdio. Это предельное значение обычно равно 255, что достаточно велико для того, чтобы потери данных при обычном использовании были достаточно редки. Тем не менее не существует способа определить, что данные были потеряны, так как система просто молча отбрасывает лишние символы.
Ситуация с выводом несколько проще. Каждый вызов fdwrite для терминала помещает символы в очередь вывода. Если очередь переполняется, то следующий вызов fdwrite будет «заблокирован» (то есть процесс будет приостановлен) до тех пор, пока очередь вывода не уменьшится до нужного уровня.
Переменные программного окружения
Программное окружение (environment) процесса – это просто набор строк, заканчивающихся нулевым символом, представленных в программе просто в виде массива указателей на строки. Эти строки называются переменными окружения (environment variables). По принятому соглашению, каждая строка окружения имеет следующую форму:
имя переменной = ее содержание
В модуле dos определены функция envcount, возвращающие количество строк окружения, и функция envstr, возвращаю строку окружения с заданным номером. Можно напрямую использовать программное окружение процесса с помощью массива envp из модуля syslinux.
В качестве простого примера следующая программа просто выводит свое окружение и завершает работу.
а) с использованием модуля dos:
(* Программа showmyenv.pas - вывод окружения *)
uses dos;
var
i:integer;
begin
for i:=1 to envcount do
writeln(envstr(i));
end.
б) с использованием модуля syslinux:
(* Программа showmyenv.pas - вывод окружения *)
uses syslinux;
var
i:integer;
begin
i:=0;
while envp[i]<>nil do
begin
writeln(envp[i]);
inc(i);
end;
end.
При запуске этой программы на одной из машин были получены следующие результаты:
CDPATH=:..:/
HOME=/usr/keith
LOGNAME=keith
MORE=-h -s
PATH=/bin:/etc:/usr/bin:/usr/cbin:/usr/lbin
SHELL=/bin/ksh
TERM=vti00
TZ=GMTOBST
Этот список может быть вам знакомым. Это окружение процесса командного интерпретатора (оболочки), вызвавшего программу showmyenv, и оно включает
такие важные переменные, как HOME и PATH.
Пример показывает, что по умолчанию окружение процесса совпадает с окружением процесса, создавшего его при помощи вызова fork или ехес. Поскольку окружение передается указанным способом, то можно записывать в окружении информацию, которую иначе пришлось бы задавать заново для каждого нового процесса. Переменная окружения TERM, в которой записан тип текущего терминала, является хорошим примером того, насколько полезным может быть использование окружения.
Чтобы задать для процесса новое окружение, необходимо использовать для его запуска один из двух вызовов из семейства exec: execle или execve. Они вызываются следующим образом:
execle(path, envp);
и:
execve(path, argv, envp);
Эти вызовы дублируют соответственно вызовы
execv и execl. Единственное различие заключается в добавлении параметра envp, который является заканчивающимся нулевым символом массивом строк, задающим окружение новой программы. Следующий пример использует вызов
execle для передачи нового программного окружения программе showmyenv:
(* Программа setmyenv.pas - установка окружения программы *)
uses linux,stdio;
const
argv:array [0..1] of pchar=('showmyenv',nil);
envp:array [0..2] of pchar=('foo=bar','bar=foo',nil);
begin
execve ('./showmyen', argv, envp);
perror ('Ошибка вызова execve');
end.
Для поиска в переменной envp имени переменной окружения, заданной в форме name=string, можно использовать стандартную библиотечную функцию getenv.
Пересылка данных
Теперь уже освоена процедура установления соединения между клиентом и сервером. Для сокетов типа SOCK_STREAM и клиент, и сервер получают дескрипторы файлов, которые могут использоваться для чтения или записи. В большинстве случаев для этого годятся обычные вызовы fdread и fdwrite. Если же необходимо задавать дополнительные параметры пересылки данных по сети, то можно использовать два новых системных вызова – send и recv. Эти вызовы имеют схожий интерфейс и ведут себя точно так же, как вызовы fdread и fdwrite, если их четвертый аргумент равен нулю.
Подключение клиента
Для выполнения запроса на подключение к серверному процессу клиент использует системный вызов connect.
Подпрограмма perror
Кроме linuxerror UNIX обеспечивает библиотечную процедуру (не системный вызов) perror. Для большинства традиционных команд UNIX использование perror является стандартным способом вывода сообщений об ошибках. Она имеет единственный аргумент строчного типа и при вызове отправляет на стандартный вывод диагностики сообщение, состоящее из переданного ей строчного аргумента, двоеточия и дополнительного описания ошибки, соответствующей текущему значению переменной linuxerror. Важно, что сообщение об ошибке отправляется на стандартный вывод диагностики, а не в стандартный вывод.
В вышеприведенном примере можно заменить строку, содержащую вызов writeln на:
perror('Ошибка при открытии файла nonesuch');
Если файл nonesuch не существует, то функция perror выведет сообщение:
Ошибка при открытии файла nonesuch: No such file or directory
Упражнение 2.17. Напишите процедуры, выполняющие те же действия, что и примитивы доступа к файлам, описанные в этой главе, но вызывающие функцию perror при возникновении ошибок или исключительных ситуаций.
Подробнее о вызове chmod
Системный вызов fstat расширяет использование вызова chmod, поскольку позволяет предварительно узнать значение кода доступа к файлу, что дает возможность изменять отдельные биты, а не менять весь код доступа целиком.
Следующая программа addx демонстрирует сказанное. Она вначале вызывает fstat для получения режима доступа к файлу из списка аргументов вызова программы. В случае успешного завершения вызова программа изменяет существующие права доступа так, чтобы файл был доступен для выполнения его владельцем. Эта программа может быть полезна для придания командным файлам, составленным пользователем, статуса исполняемых файлов.
(* Программа addx разрешает доступ на выполнение файла *)
uses linux,stdio;
const XPERM=0100; (* Право на выполнение для владельца *)
var
k:integer;
statbuf:tstat;
begin
(* Выполнить для всех файлов в списке аргументов *)
for k := 1 to paramcount do
begin
(* Получить текущий код доступа к файлу *)
if not fstat(paramstr(k), statbuf) then
begin
writeln('addx: ошибка вызова stat для ',paramstr(k));
continue;
end;
(*
Попытаться разрешить доступ на выполнение
при помощи оператора побитового ИЛИ
*)
statbuf.mode := statbuf.mode or octal(XPERM);
if not chmod (paramstr(k), statbuf.mode) then
writeln('addx: ошибка изменения прав доступа для файла ', paramstr(k));
end; (* Конец цикла *)
halt(0);
end.
Наиболее интересный момент заключается здесь в способе изменения кода доступа файла при помощи побитового оператора ИЛИ. Это гарантирует, что устанавливается бит, заданный определением XPERM. Фактически мы могли бы расписать этот оператор в виде:
statbuf.mode := statbuf.mode or octal(XPERM);
Для ясности использована более короткая форма. Можно было бы также использовать вместо XPERM предусмотренную в системе постоянную STAT_IXUSR.
Упражнение 3.11. Приведенную задачу можно решить проще. Если вы знаете, как это сделать, напишите эквивалент этой программы при помощи командного интерпретатора.
Упражнение 3.12. Напишите свою версию команды chmod, используя ее описание в справочном руководстве вашей системы UNIX.
Поле c_cflag
Поле c_cflag содержит параметры, управляющие состоянием порта терминала. Обычно процессу не нужно изменять значения поля c_cflag своего управляющего терминала. Изменения этого поля могут понадобиться специальным коммуникационным приложениям, или программам, открывающим коммуникационные линии для дополнительного оборудования, например, для принтера. Значения поля c_cflag образуются объединением при помощи операции ИЛИ битовых констант, определенных в файле stdio. В общем случае каждая константа представляет бит поля c_cflag, который может быть установлен или сброшен. Не будем объяснять назначение всех битов этого поля (за полным описанием обратитесь к справочному руководству системы). Тем не менее есть четыре функции, которые позволяют опрашивать и устанавливать скорость ввода и вывода, закодированную в этом поле, не беспокоясь о правилах манипулирования битами.
Поле c_iflag
Поле c_iflag в структуре termios служит для общего управления вводом с терминала. Не будем рассматривать все возможные установки, а выберем из них только наиболее общие.
Три из связанных с этим полем флага связаны с обработкой символа возврата каретки. Они могут быть полезны в терминалах, которые посылают для обозначения конца строки последовательность, включающую символ возврата каретки CR. ОС UNIX, конечно же, ожидает в качестве символа конца строки символ LF (line feed) или символ перевода строки ASCII, символ NL (new line). Следующие флаги могут исправить ситуацию:
INLCR Преобразовывать символ новой строки в возврат каретки
IGNCR Игнорировать возврат каретки
ICRNL Преобразовывать возврат каретки в символ новой строки
Три других поля c_iflag связаны с управлением потоком данных:
IXON Разрешить старт/стопное управление выводом
IXANY Продолжать вывод при нажатии любого символа
IXOFF Разрешить старт/стопное управление вводом
Флаг IXON дает пользователю возможность управления выводом. Если этот флаг установлен, то пользователь может прервать вывод, нажав комбинацию клавиш Ctrl+S. Вывод продолжится после нажатия комбинации Ctrl+Q. Если также установлен параметр IXANY, то для возобновления приостановленного вывода достаточно нажатия любой клавиши, хотя для остановки вывода должна быть нажата именно комбинация клавиш Ctrl+S. Если установлен флаг IXOFF, то система сама пошлет терминалу символ остановки (как обычно, Ctrl+S), когда буфер ввода будет почти заполнен. После того как система будет снова готова к приему данных, для продолжения ввода будет послана комбинация символов Ctrl+Q.
Поле c_oflag
Поле с_оflag позволяет управлять режимом вывода. Наиболее важным флатом в этом поле является флаг OPOST. Если он не установлен, то выводимые символы передаются без изменений. В противном случае символы подвергаются обработке, заданной остальными флагами, устанавливаемыми в поле
c_oflag. Некоторые из них вызывают подстановку символа возврата каретки (CR) при выводе на терминал:
ONLCR | Преобразовать символ возврата каретки (CR) в символ возврата каретки (CR) и символ перевода строки (NL) | ||
OCRNL | Преобразовать символ возврата каретки (CR) в символ перевода строки (NL) | ||
ONOCR | Не выводить символ возврата каретки (CR) в нулевом столбце | ||
ONLRET | Символ перевода строки (NL) выполняет функцию символа возврата каретки (CR) |
Если установлен флаг ONLCR, то символы перевода строки NL
преобразуются в последовательность CR+NL (символ возврата каретки и символ перевода строки). Это гарантирует, что каждая строка будет начинаться с левого края экрана. И наоборот, если установлен флаг OCRNL, то символ возврат каретки будет преобразовываться в символ перевода строки. Установка флага
ONLRET сообщает драйверу терминала, что для используемого терминала символы перевода строки будут автоматически выполнять и возврат каретки. Если установлен флаг ONOCR, то символ возврата каретки не будет посылаться при выводе строки нулевой длины.
Большинство остальных флагов поля c_oflag относятся к задержкам в передаче, связанным с интерпретацией специальных символов, таких как перевод строки, табуляция, перевод страницы и др. Эти задержки учитывают время позиционирования указателя знакоместа, где должен быть выведен следующий символ на экране или принтере. Подробное описание этих флагов должно содержать справочное руководство системы.
Поле с_lflag
Возможно, наиболее интересным элементом структуры termios для программиста является поле c_lflag. Оно используется текущей дисциплиной линии связи для управления функциями терминала. Это поле содержит следующие флаги:
ICANON | Канонический построчный ввод | ||
ISIG | Разрешить обработку прерываний | ||
IEXTEN | Разрешить дополнительную (зависящую от реализации) обработку вводимых символов | ||
ECHO | Разрешить отображение вводимых символов на экране | ||
ЕСНОЕ | Отображать символ удаления как возврат-пробел-возврат | ||
ЕСНОК | Отображать новую строку после удаления строки | ||
ECHONL | Отображать перевод строки | ||
NOFLSH | Отменить очистку буфера ввода после прерывания | ||
TOSTOP | Посылать сигнал SIGTTOU при попытке вывода фонового процесса |
Если установлен флаг ICANON, то включается канонический режим работы терминала. Как уже было видно выше, это позволяет использовать символы редактирования строки в процессе построчного ввода. Если флаг ICANON не установлен, то терминал находится в режиме прямого доступа (raw mode), который чаще всего используется полноэкранными программами и коммуникационными пакетами. Вызовы read будут при этом получать данные непосредственно из очереди ввода. Другими словами, основной единицей ввода будет одиночный символ, а не логическая строка. Программа при этом может считывать данные по одному символу (что обязательно для экранных редакторов) или большими блоками фиксированного размера (что удобно для коммуникационных программ). Но для того чтобы полностью управлять поведением вызова fdread, программист должен задать еще два дополнительных параметра. Это параметр VMIN, наименьшее число символов, которые должны быть приняты до возврата из вызова read, и параметр VTIME, максимальное время ожидания для вызова fdread. Оба параметра записываются в массиве с_сс. Это важная тема, которая будет подробно изучена в следующем разделе. А пока просто обратим внимание на то, как в следующем примере сбрасывается флаг ICANON.
uses stdio, linux;
var
tdes:termios;
.
.
.
tcgetattr(0, tdes);
tdes.c_lflag := tdes.c_lflag and (not ICANON);
tcsetattr(0, TCSAFLUSH, tdes);
Если установлен флаг ISIG, то разрешается обработка клавиш прерывания (intr) и аварийного завершения (quit).
Обычно это позволяет пользователю завершить выполнение программы. Если флаг ISIG не установлен, то проверка не выполняется, и символы intr и quit передаются программе без изменений.
Если установлен флаг ECHO, то символы будут отображаться на экране по мере их набора. Сброс этого флага полезен для процедур проверки паролей и программ, которые используют клавиатуру для особых функций, например, для перемещения курсора или команд экранного редактора.
Если одновременно установлены флаги ЕСНОЕ и ECHO, то символ удаления будет отображаться как последовательность символов backspace-space-backspace (возврат–пробел–возврат). При этом последний символ на терминале немедленно стирается с экрана, и пользователь видит, что символ действительно был удален. Если флаг ЕСНОЕ установлен, а флаг ECHO нет, то символ удаления будет отображаться как space-backspace, тогда при его вводе будет удаляться символ в позиции курсора алфавитно-цифрового терминала.
Если установлен флаг ECHONL, то перевод строки будет всегда отображать на экране, даже если отображение символов отключено, что может быть полезным при выполнении самим терминалом локального отображения вводима символов. Такой режим часто называется полудуплексным режимом (half-duplex mode).
Последним флагом, заслуживающим внимания в этой группе флагов, является флаг NOFLSH, который подавляет обычную очистку очередей ввода и вывод при нажатии клавиш intr и quit
и очистку очереди ввода при нажатии клавиши susp.
Альтернативой TCGetAttr может быть вызов IOCtl:
uses Linux;
var
tios : Termios;
begin
IOCtl(1,TCGETS,@tios);
WriteLn('Input Flags : $',hexstr(tios.c_iflag,8));
WriteLn('Output Flags : $',hexstr(tios.c_oflag,8));
WriteLn('Line Flags : $',hexstr(tios.c_lflag,8));
WriteLn('Control Flags: $',hexstr(tios.c_cflag,8));
end.
Для удобства изменения параметров терминала в файле linux определена функция CFMakeRaw:
Получение информации о файле: вызов fstat
До сих пор были лишь рассмотрены вопросы, как можно установить или изменить основные связанные с файлами свойства. Системный вызов fstat позволяет процессу определить значения этих свойств в существующем файле.
Получение параметров локальной системы
В книге были рассмотрены некоторые процедуры, сообщающие системные ограничения (например, pathconf). Есть также и другие процедуры, служащие для той же цели:
sysconf | Обеспечивает доступ к конфигурационным параметрам, находящимся в файлах <limits.h> и <unistd.h> | ||
SysInfo | Возвращает информацию о системе | ||
GetHostName | Возвращает имя локального компьютера | ||
uname | Возвращает указатель на структуру utsname, содержащую название операционной системы, имя узла, которое может использоваться системой в сети для установления связи, а также номер версии системы
UNIX | ||
getpwent | Это семейство процедур обеспечивает доступ к данным из файла паролей /etc/passwd. Все следующие вызовы возвращают указатель на структуру passwd, определенную в файле <pwd.h>:
getpwnam(const char *username); getpwuid(uid_t uid); getpwent(void); | ||
getgrent | Это семейство процедур связано с доступом к файлу описания групп /etc/group | ||
getrlimit | Обеспечивает доступ к предельным значениям системных ресурсов, таких как память или доступное дисковое пространство | ||
getlogin
cuserid | Получает имя пользователя для текущего процесса |
Пример использования SysInfo:
Uses Linux;
Function Mb(L : Longint) : longint;
begin
Mb:=L div (1024*1024);
end;
Var Info : TSysInfo;
D,M,Secs,H : longint;
begin
If Not SysInfo(Info) then
Halt(1);
With Info do
begin
D:=Uptime div (3600*24);
UpTime:=UpTime mod (3600*24);
h:=uptime div 3600;
uptime:=uptime mod 3600;
m:=uptime div 60;
secs:=uptime mod 60;
Writeln('Uptime : ',d,'days, ',h,' hours, ',m,' min, ',secs,' s.');
Writeln('Loads : ',Loads[1],'/',Loads[2],'/',Loads[3]);
Writeln('Total Ram : ',Mb(totalram),'Mb.');
Writeln('Free Ram : ',Mb(freeram),'Mb.');
Writeln('Shared Ram : ',Mb(sharedram),'Mb.');
Writeln('Buffer Ram : ',Mb(bufferram),'Mb.');
Writeln('Total Swap : ',Mb(totalswap),'Mb.');
Writeln('Free Swap : ',Mb(freeswap),'Mb.');
end;
end.
Пример использования uname:
Uses linux;
Var UN : utsname;
begin
if Uname (UN) then
With UN do
begin
Writeln ('Name : ',pchar(@sysname[0]));
Writeln ('Nodename : ',pchar(@Nodename[0]));
Writeln ('release : ',pchar(@Release[0]));
Writeln ('Version : ',pchar(@Version[0]));
Writeln ('Machine : ',pchar(@Machine[0]));
Writeln ('Domainname : ',pchar(@domainname[0]));
end;
end.
Пользователи и права доступа
Для каждого файла в системе UNIX задан его владелец
(owner – один из пользователей системы; обычно пользователь, создавший файл). Истинный идентификатор пользователя представлен неотрицательным числом user-id, сокращенно uid, которое связывается с файлом при его создании.
В типичной системе UNIX связанный с определенным именем пользователя идентификатор uid находится в третьем поле записи о пользователе в файле паролей, то есть в строке файла /etc/passwd/, которая идентифицирует пользователя в системе. Типичная запись
keith:x:35:10::/usr/keith:/bin/ksh
указывает, что пользователь keith имеет uid 35.
Поля в записи о пользователе в файле паролей разделяются двоеточием. Первое поле задает имя пользователя. Второе, в данном случае х, – это маркер пароля пользователя. В отличие от ранних версий UNIX сам зашифрованный пароль обычно находится в другом файле, отличающемся для разных систем. Как уже было показано, третье поле содержит идентификатор пользователя uid. В четвертом поле находится идентификатор группы пользователя по умолчанию – group-id, сокращенно gid; подробнее он будет рассмотрен ниже. Пятое поле – это необязательное поле комментария. Шестое задает домашний каталог пользователя. Последнее поле – полное имя программы, которая запускается после входа пользователя в систему. Например, /bin/ksh – одна из стандартных оболочек UNIX.
Фактически для идентификации пользователя в системе UNIX нужен только идентификатор user-id. Каждый процесс UNIX обычно связывается с идентификатором пользователя, который запустил его на выполнение. При этом процесс является просто экземпляром выполняемой программы. При создании файла система устанавливает его владельца на основе идентификатора uid, создающего файл процесса.
Владелец файла позже может быть изменен, но только суперпользователем или владельцем файла. Следует отметить, что суперпользователь имеет имя root и его идентификатор uid всегда равен 0.
Помимо владельца файлы могут быть связаны с группами пользователей
(groups) которые представляют произвольный набор пользователей, благодаря чему становится возможным простой способ управления проектами, включающими несколько человек. Каждый пользователь принадлежит как минимум к одной группе.
Группы пользователей определяются в файле /etc/group. Каждая из них определена своим идентификатором gid, который, как и uid, является неотрицательным числом. Группа пользователя по умолчанию задается четвертым полем записи о нем в файле паролей.
Так же, как идентификатор пользователя uid, идентификатор группы gid пользователя наследуется процессом, который запускает пользователь. Поэтому при создании файла связанный с создающим его процессом идентификатор группы gid записывается наряду с идентификатором пользователя uid.
Понятие процесса
Как было уже рассмотрено в главе 1, процессом в терминологии UNIX является просто экземпляр выполняемой программы, соответствующий определению задачи в других средах. Каждый процесс объединяет код программы, значения данных в переменных программы и более экзотические элементы, такие как значения регистров процессора, стек программы и т.д.[4]
Командный интерпретатор для выполнения команд обычно запускает один или несколько процессов. Например, командная строка
$ cat file1 file2
приведет к созданию процесса для выполнения команды cat. Немного более сложная команда
$ ls | wc -l
приведет к созданию двух процессов для одновременного выполнения команд ls и wc. (Кроме этого, результат программы ls, вывод списка файлов в каталоге, перенаправляется
с помощью программного канала (pipe) на вход программы подсчета числа слов wc.)
Так как процессы соответствуют выполняемым программам, не следует путать их с программами, которые они выполняют. Несколько процессов могут выполнять одну и ту же программу. Например, если несколько пользователей выполняют одну и ту же программу редактора, то каждый из экземпляров программы будет отдельным процессом.
Любой процесс UNIX может, в свою очередь, запускать другие процессы. Это придает среде процессов UNIX иерархическую структуру, подобную дереву каталогов файловой системы. На вершине дерева процессов находится единственный управляющий процесс, экземпляр очень важной программы init, которая является предком всех системных и пользовательских процессов.
Система UNIX предоставляет программисту набор системных вызовов для создания процессов и управления ими. Если исключить различные средства для межпроцессного взаимодействия, то наиболее важными из оставшихся будут:
fork | Используется для создания нового процесса, дублирующего вызывающий. Вызов fork является основным примитивом создания процессов | ||
ехес | Семейство библиотечных процедур и один системный вызов, выполняющих одну и ту же функцию – смену задачи процесса за счет перезаписи его пространства памяти новой программой. Различие между вызовами ехес в основном лежит в способе задания списка их аргументов | ||
wait | Этот вызов обеспечивает элементарную синхронизацию процессов. Он позволяет процессу ожидать завершения другого процесса, обычно логически связанного с ним | ||
halt | Используется для завершения процесса |
Далее рассмотрим, что представляют собой процессы UNIX в целом и вышеприведенные четыре важных системных вызова в частности.
Порты
Кроме адреса компьютера, клиентская программа должна иметь возможность подключения к нужному серверному процессу. Серверный процесс ждет подключения к заданному номеру порта (port number). Поэтому клиентский процесс должен выполнить запрос на подключение к определенному порту на заданном компьютере. Если продолжить аналогию с пересылкой писем по почте, то это равносильно дополнению адреса номером комнаты или квартиры.
Некоторые номера портов по соглашению считаются отведенными для стандартных сервисов, таких как ftp или rlogin. Эти номера портов записаны в файле /etc/services. В общем случае порты с номерами, меньшими 1024, считаются зарезервированными для системных процессов UNIX. Все остальные порты доступны для пользовательских процессов.
Построчный ввод и вывод
Существует также набор простых процедур для ввода и вывода строк (под которыми понимается последовательность символов, завершаемая символом перевода строки). Эти процедуры удобно использовать в интерактивных программах, которые выполняют чтение с клавиатуры и вывод на экран терминала. Основные процедуры для ввода строк называются gets и fgets.
Посылка сигналов другим процессам: вызов kill
Процесс вызывает процедуру sigaction для установки реакции на поступление сигнала. Обратную операцию, посылку сигнала, выполняет системный вызов kill, описанный следующим образом:
Посылка сигналов самому процессу: вызовы sigraise и alarm
Функция sigraise просто посылает сигнал выполняющемуся процессу:
Потоки управления
Потоки управления, или нити (threads) являются облегченной версией процессов – поддерживающие их системы позволяют выполнять одновременно несколько таких потоков в рамках одного процесса, при этом все потоки могут работать с данными процесса. Их применение может быть очень ценным для повышения производительности и интерактивности определенных классов задач, но техника программирования многопотоковых программ является довольно сложной. Многие версии
UNIX поддерживали различные подходы к организации потоков выполнения, но теперь выработана стандартная модель (POSIX threads), включенная в стандарт POSIX и пятую версию спецификации XSI. Интерфейс функций работы с потоками управления может быть описан в справочном руководстве системы под заголовком pthread_.
Для создания потока может использоваться вызов Clone:
Права доступа и режимы файлов
Владелец обладает исключительными правами обращения с файлами. В частности, владелец может изменять связанные с файлом права доступа
(permissions). Права доступа определяют возможности доступа к файлу других пользователей. Они затрагивают три группы пользователей:
1)
владелец файла;
2) все пользователи, кроме владельца файла, принадлежащие к связанной с файлом группе;
3) все пользователи, не входящие в категории 1 или 2.
Для каждой категории пользователей существуют три основных типа прав доступа к файлам. Они определяют, может ли пользователь определенной категории выполнять:
– чтение из файла;
– запись в файл;
– запуск файла на выполнение. В этом случае файл обычно является программой или последовательностью команд оболочки.
Как обычно, суперпользователь выделен в отдельную категорию и может оперировать любыми файлами, независимо от связанных с ними прав чтения, записи или выполнения.
Система хранит связанные с файлом права доступа в битовой маске, называемой кодом доступа к файлу (file mode). Хотя модуль linux и определяет символьные имена для битов прав доступа, большинство программистов все еще предпочитает использовать восьмеричные постоянные, приведенные в табл. 3.1 – при этом символьные имена являются относительно недавним и весьма неудобным нововведением. Следует обратить внимание, что в языке С восьмеричные постоянные всегда начинаются с нуля, иначе компилятор будет расценивать их как десятичные. В Паскале же для записи восьмеричных чисел удобно использовать функцию octal, параметром которой является восьмеричное число, записанное десятичными числами, а результатом – значение в десятеричной системе:
Права доступа к каталогам
Так же как и с обычными файлами, с каталогами связаны права доступа, определяющие возможность доступа к ним различных пользователей.
Права доступа к каталогам организованы точно так же, как и права доступа к обычным файлам, разбиты на три группы битов rwx, определяющих права владельца файла, пользователей из его группы и всех остальных пользователей системы.
Тем не менее, хотя эти права доступа представлены так же, как и у обычных файлов, интерпретируются они по-другому:
– право доступа к каталогу на чтение показывает, что соответствующий класс пользователей может выводить список содержащихся в каталоге файлов и подкаталогов. Однако это не означает, что пользователи могут читать содержащуюся в файлах информацию – это определяется правами доступа к отдельным файлам;
– право доступа к каталогу на запись позволяет пользователю создавать в каталоге новые файлы и удалять существующие. И снова это не дает пользователю права изменять содержимое существующих файлов, если это не разрешено правами доступа к отдельным файлам. Вместе с тем при этом можно удалить существующий файл и создать новый с тем же самым именем, и это, по сути, означает то же самое, что и изменение содержимого исходного файла;
– право доступа к каталогу на выполнение, называемое также правом выполнения, или правом прохождения, поиска
(search permission), позволяет пользователю перейти в каталог при помощи команды cd или системного вызова chdir в программе (который будет рассмотрен позже). Кроме этого, чтобы иметь возможность открыть файл или выполнить программу, пользователь должен иметь право доступа на выполнение для всех ведущих к файлу каталогов, входящих в абсолютный путь файла;
– бит фиксации, STAT_ISVTX, позволяет установить дополнительную защиту файлов, находящихся в каталоге. Из такого каталога пользователь может удалить только те файлы, которыми он владеет или на которые он имеет явное право доступа на запись, даже при наличии права на запись в каталог. Примером является каталог /tmp.
Каталог ben |
||||||
123 |
. |
\0 |
||||
247 |
. |
. |
\0 |
|||
260 |
b |
o |
o |
k |
\0 |
|
401 |
m |
e |
m |
o |
s |
\0 |
Каталог book |
||||||
260 |
. |
\0 |
||||
123 |
. |
. |
\0 |
|||
566 |
c |
h |
a |
p |
1 |
\0 |
567 |
c |
h |
a |
p |
2 |
\0 |
590 |
c |
h |
a |
p |
3 |
\0 |
Каталог memos |
||||||
401 |
. |
\0 |
||||
123 |
. |
. |
\0 |
|||
800 |
k |
h |
\0 |
|||
810 |
k |
d |
\0 |
|||
077 |
m |
w |
\0 |
На уровне командного интерпретатора связанные с каталогами права доступа можно вывести при помощи команды ls с параметром -l. Подкаталоги будут обозначаться буквой d
в первой позиции, например:
$ ls -l
total 168
-rw-r----- 1 ben other 39846 Oct 12 21:21 dir_t
drwxr-x--- 2 ben other 32 Oct 12 22:02 expenses
-rw-r----- 1 ben other 46245 Oct 13 10:34 new
-rw-r----- 1 ben other 3789 Sep 2 18:40 pwd_text
-rw-r----- 1 ben other 1310 Sep 13 10:38 test.с
Здесь строка, описывающая подкаталог expenses, помечена буквой d
в начале строки. Видно, что владелец этого каталога (пользователь ben) имеет права на чтение, запись и выполнение (поиск), пользователи группы файла (называющейся other) имеют права на чтение и выполнение (переход в каталог), а для всех остальных пользователей доступ полностью запрещен.
Если требуется получить информацию о текущем каталоге, можно задать в команде ls
кроме параметра -l еще и параметр -d, например:
$ ls -ld
drwxr-x--- 3 ben other 128 Oct 12 22:02 .
Помните, что имя .
(точка) в конце листинга обозначает текущий каталог.
Предостережение
Здесь необходимо сделать несколько предостережений. Во-первых, существует предельное число файлов, которые могут быть одновременно открыты программой, – в стандарте POSIX (а следовательно, и в спецификации XSI) не менее двадцати[1]. Чтобы обойти эту проблему, требуется использовать системный вызов fdclose, тем самым сообщая системе, что работа с файлом закончена. Вызов fdclose будет рассмотрен в разделе 2.1.5. Может также существовать предел суммарного числа файлов, открытых всеми процессами, определяемый размером таблицы в ядре. Во-вторых, в ранних версиях UNIX и в параметре flags непосредственно задавались численные значения. Это все еще достаточно распространенный, хотя и не совсем удовлетворительный прием – задание численных значений вместо имен постоянных, определенных в модуле linux. Поэтому может встретиться оператор типа
filedes := fdopen(filename, 0);
который в обычных условиях открывает файл только для чтения и эквивалентен следующему оператору:
filedes := fdopen (filename, Open_RDONLY);
Упражнение 2.1. Создайте небольшую программу, описанную выше. Проверьте ее работу при условии, что файл junk не существует. Затем создайте файл junk с помощью текстового редактора и снова запустите программу. Содержимое файла junk не имеет значения.
Преобразование строк в числовые значения
Стандарт ANSI С определяет два набора функций для преобразования строк в числовые величины:
Прием и передача UDP-сообщений
Для сокетов UDP есть два новых системных вызова –
sendto и recvfrom. Параметр sockfd в обоих вызовах задает связанный с локальным адресом сокет, через который принимаются и передаются пакеты.
Прием запроса на установку TCP-соединения
Когда сервер получает от клиента запрос на соединение, он должен создать новый сокет для работы с новым соединением. Первый же сокет используется только для установки соединения. Дополнительный сокет создается при помощи вызова accept, принимающего очередное соединение.
История UNIX
ОС UNIX начала свою историю с того момента, как в 1969 г. Кен Томсон (Ken Thomson) и Деннис Ричи (Dennis Ritchie) с коллегами начали работу над ней на «стоящем в углу свободном компьютере PDP-7». С тех пор ОС UNIX нашла применение в сфере бизнеса и образования, а также стала основой ряда международных стандартов.
Кратко перечислим некоторые вехи истории UNIX:
–
шестая редакция системы, 1975 (Sixth Edition, или Version 6). Первый широко известный в техническом сообществе коммерческий вариант и основа первой версии Berkeley UNIX;
– Xenix (1980). Версия от Microsoft – один из коммерческих вариантов UNIX с измененным названием, возникших в начале восьмидесятых годов;
– System V (1983-92). Одна из наиболее важных версий от создателя UNIX – корпорации AT&T. Наследница Version 7 и последовавшей за ней System III;
– Berkeley UNIX (версия 4.2 в 1984 г., 4.4 в 1993 г.). Разработанная в университете Berkeley, эта версия также была одной из наиболее важных версий UNIX и ввела в семейство UNIX много новых средств;
– POSIX (с 1988 г. и далее). Ключевой набор стандартов комитета IEEE (см. ниже), сыгравший важную роль в развитии UNIX;
– Open Portability Guides (XPG3 в 1990 г., XPG4.2 в 1994 г.). Практическая спецификация, объединившая целый ряд основных стандартов и рецептов использования UNIX систем. Консорциум Х/Open в конце концов приобрел торговую марку UNIX.
Кроме того, существовало множество коммерческих взаимодействий, таких как передача торговой марки UNIX от компании AT&T к компании Novell, а затем консорциуму Х/Open, а также слияние организаций Х/Open и Open Software Foundation. Однако это достаточно упрощенный взгляд на историю UNIX. На самом деле дерево семейства UNIX является очень сложным.
Приложение Модуль stdio
Назначение модуля – восполнить недостаток средств прикладного и системного программирования на языке Паскаль аналогичными средствами библиотек языка Си.
unit stdio;
{$mode objfpc}
interface
(* A streammarker remembers a position in a buffer. *)
uses linux,sockets;
const
EOF=-1; (* признак конца файла для stdio *)
WCOREFLAG=$80; (* флаг сброса дампа памяти *)
(* Размер буфера для чтения и записи *)
BUFSIZ=8192;
NULL=nil;
_IOFBF=0; (* setvbuf should set fully buffered *)
_IOLBF=1; (* setvbuf should set line buffered *)
_IONBF=2; (* setvbuf should set unbuffered *)
MAX_INPUT=255; (* size of the type-ahead buffer *)
_SIGSET_NWORDS=1024 div (8 * sizeof (longint)); (* sizeof(sigset_t) *)
(* флаги для pathconf/fpathconf *)
(* returns the maximum number of links to the file. If filedes or
* path refer to a directory, then the value applies to the whole
* directory.
*)
_PC_LINK_MAX=0;
(* returns the maximum length of a formatted input line, where
* filedes or path must refer to a terminal.
*)
_PC_MAX_CANON=1;
(* returns the maximum length of an input line, where filedes or
* path must refer to a terminal.
*)
_PC_MAX_INPUT=2;
(* returns the maximum length of a filename in the directory path
* or filedes. the process is allowed to create.
*)
_PC_NAME_MAX=3;
(* returns the maximum length of a relative pathname when path or
* filedes is the current working directory.
*)
_PC_PATH_MAX=4;
(* returns the size of the pipe buffer, where filedes must refer to
* a pipe or FIFO and path must refer to a FIFO.
*)
_PC_PIPE_BUF=5;
(* returns nonzero if the chown(2) call may not be used on this
* file. If filedes or path refer to a directory, then this
* applies to all files in that directory.
*)
_PC_CHOWN_RESTRICTED=6;
(* returns nonzero if accessing filenames longer than
аа * _POSIX_NAME_MAXа generates an error.
аа *)
а _PC_NO_TRUNC=7;
а (* returns nonzero if special character processing can be disabled,
аа * where filedes or path must refer to a terminal.
аа *)
а _PC_VDISABLE=8;
а _PC_SYNC_IO=9;
а _PC_ASYNC_IO=10;
а _PC_PRIO_IO=11;
а _PC_SOCK_MAXBUF=12;
а _PC_FILESIZEBITS=13;
а _PC_REC_INCR_XFER_SIZE=14;
а _PC_REC_MAX_XFER_SIZE=15;
а _PC_REC_MIN_XFER_SIZE=16;
а _PC_REC_XFER_ALIGN=17;
а _PC_ALLOC_SIZE_MIN=18;
а _PC_SYMLINK_MAX=19;
а (* For posix fcntl() and `l_type' field of a `struct flock' for lockf().а *)
а F_RDLCK=0;аааааа (* Read lock.а *)
а F_WRLCK=1;ааа ааа(* Write lock.а *)
а F_UNLCK=2;аааааа (* Remove lock.а *)
а F_DUPFD=0;аааааа (* Duplicate fildes *)
а (* Constants for ulimit *)
а UL_GETFSIZE=1;ааааа (* тючтЁр•рхЄ єёЄрэютыхээюх юуЁрэшўхэшх эр ЁрчьхЁ
аааааааааааааааааааааааа Їрщыр (т сыюърї яю 512 срщЄ) *)
а UL_SETFSIZE=2;ааааа (* єёЄрэртыштрхЄ яЁхфхы№эvщ ЁрчьхЁ Їрщыр *)
а __UL_GETMAXBRK=3;аа (* тючтЁр•рхЄ ьръёшьры№эю тючьюцэvщ рфЁхё ёхуьхэЄр фрээvї *)
а __UL_GETOPENMAX=4;а (* тючтЁр•рхЄ ьръёшьры№эюх ъюышўхёЄтю Їрщыют, ъюЄюЁюх
аааааааааааааааааааааааа яЁюЎхёё ьюцхЄ юЄъЁvЄ№ *)
а FD_SETSIZE=64;
а
а (* Macros used as `request' argument to `ioctl'.а *)
а __SID=byte('S') shl 8;
а I_NREADаааа =__SID or 1;а (* Counts the number of data bytes in the data
аааааааааааааааааааааааааааааа block in the first message.а *)
а I_PUSHааааа =__SID or 2;а (* Push STREAMS module onto top of the current
аааааааааааааааааааааааааааааа STREAM, just below the STREAM head.а *)
а I_POPаааааа =__SID or 3;а (* Remove STREAMS module from just below the
аааааааааааааааааааааааааааааа STREAM head.а *)
а I_LOOKааааа =__SID or 4;а (* Retrieve the name of the module just below
аааааааааааааааааааааааааааааа the STREAM head and place it in a character
аааааааааааааааааааааааааааааа string.а *)
а I_FLUSHаааа =__SID or 5;а (* Flush all input and/or output.а *)
а I_SRDOPTааа =__SID or 6;а (* Sets the read mode.а *)
а I_GRDOPTааа =__SID or 7;а (* Returns the current read mode setting.а *)
а I_STRаааааа =__SID or 8;а (* Construct an internal STREAMS `ioctl'
аааааааааааааааааааааааааааааа message and send that message downstream. *)
а I_SETSIGааа =__SID or 9;а (* Inform the STREAM head that the process
ааааааааааааааааааа аааааааааааwants the SIGPOLL signal issued.а *)
а I_GETSIGааа =__SID or 10; (* Return the events for which the calling
аааааааааааааааааааааааааааааа process is currently registered to be sent
аааааааааааааааааааааааааааааа a SIGPOLL signal.а *)
а I_FINDа аааа=__SID or 11; (* Compares the names of all modules currently
аааааааааааааааааааааааааааааа present in the STREAM to the name pointed to
аааааааааааааааааааааааааааааа by `arg'.а *)
а I_LINKааааа =__SID or 12; (* Connect two STREAMs.а *)
а I_UNLINKааа =__SID or 13; (* Disconnects the two STREAMs.а *)
а I_PEEKааааа =__SID or 15; (* Allows a process to retrieve the information
аааааааааааааааааааааааааааааа in the first message on the STREAM head read
аааааааааааааааааааааааааааааа queue without taking the message off the
аааааааааааааааааааааааааааааа queue.а *)
а I_FDINSERTа =__SID or 16; (* Create a message from the specifiedааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааа
аааааааааааааааааааааааааааааа buffer(s), adds information about anotherаааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааа
аааааааааааааааааааааааааааааа STREAM, and send the message downstream.а *)
а I_SENDFDааа =__SID or 17; (* Requests the STREAM associated with `fildes'
аааааааааааааааааааааааааааааа to send a message, containing a file
аааааааааааааааааааааааааааааа pointer, to the STREAM head at the other end
аааааааааааааааа ааааааааааааааof a STREAMS pipe.а *)
а I_RECVFDааа =__SID or 14; (* Non-EFT definition.а *)
а I_SWROPTааа =__SID or 19; (* Set the write mode.а *)
а I_GWROPTааа =__SID or 20; (* Return the current write mode setting.а *)
а I_LISTааааа =__SID or 21; (* List all the module names on the STREAM, up
аааааааааааааааааааааааааааааа to and including the topmost driver name. *)
а I_PLINKаааа =__SID or 22; (* Connect two STREAMs with a persistent
ааааааааааааааааааааааааааааааа link.а *)
а I_PUNLINKаа =__SID or 23; (* Disconnect the two STREAMs that were
аааааааааааааааааааааааааааааа connected with a persistent link.а *)
а I_FLUSHBAND =__SID or 28; (* Flush only band specified.а *)
а I_CKBANDааа =__SID or 29; (* Check if the message of a given priority
ааааааааааааа аааааааааааааааааband exists on the STREAM head read
аааааааааааааааааааааааааааааа queue.а *)
а I_GETBANDаа =__SID or 30; (* Return the priority band of the first
аааааааааааааааааааааааааааааа message on the STREAM head read queue.а *)
а I_ATMARKааа =__SID or 31; (* See if the current message on the STREAM
аааааааааааааааааааааааааааааа head read queue is "marked" by some module
аааааааааааааааааааааааааааааа downstream.а *)
а I_SETCLTIME =__SID or 32; (* Set the time the STREAM head will delay when
аааа ааааааааааааааааааааааааааa STREAM is closing and there is data on
аааааааааааааааааааааааааааааа the write queues.а *)
а I_GETCLTIME =__SID or 33; (* Get current value for closing timeout.а *)
а I_CANPUTааа =__SID or 34; (* Check if a certain band is writable.а *)
а (* фы шэЄхЁЇхщёр ёюъхЄют *)а
а INADDR_ANY=0;
а { Maximum queue length specificable by listen.аа }
а SOMAXCONN = 5;
а { Flags we can use with send/ and recv.а }
а { process out-of-band dataа }
а MSG_OOB = $1;
а { peek at incoming messageа }
ааMSG_PEEK = $2;
а { send without using routing tablesа }
а MSG_DONTROUTE = $4;
а { Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxxа }
а SOL_IP = 0;
а SOL_IPX = 256;
а SOL_AX25 = 257;
а SOL_ATALK = 258;
а SOL_NETROM = 259;
а SOL_TCP = 6;
а SOL_UDP = 17;
а { IP optionsа }
а IPTOS_LOWDELAY = $10;
а IPTOS_THROUGHPUT = $08;
а IPTOS_RELIABILITY = $04;
а { These need to appear somewhere around hereа }
а IP_DEFAULT_MULTICAST_TTL = 1;
а IP_DEFAULT_MULTICAST_LOOP = 1;
а IP_MAX_MEMBERSHIPS = 20;
а { IP options for use with WinSockа }
а IP_OPTIONS = 1;
а IP_MULTICAST_IF = 2;
а IP_MULTICAST_TTL = 3;
а IP_MULTICAST_LOOP = 4;
а IP_ADD_MEMBERSHIP = 5;
а IP_DROP_MEMBERSHIP = 6;
а IP_TTL = 7;
а IP_TOS = 8;
а IP_DONTFRAGMENT = 9;
а { IPX optionsа }
а IPX_TYPE = 1;
а { TCP options }
а TCP_NODELAY = $0001;
а TCP_MAXSEG = 2;
а { The various priorities.а }
а SOPRI_INTERACTIVE = 0;
а SOPRI_NORMAL = 1;
а SOPRI_BACKGROUND = 2;
а (* єяЁртыхэшх ЄхЁьшэрыюь *)
а TCOOFF = 0;
а TCOON = 1;
а TCIOFF = 2;
а TCION = 3;
а TCGETA = 5;
а TCSETA = 6;
а TCSETAW = 7;
а TCSETAF = 8;
а TCIFLUSH = 0;
а TCOFLUSH = 1;
а TCIOFLUSH = 2;
а TCFLSH = 3;
а TCSAFLUSH = 1;
а TCSANOW = 2;
а TCSADRAIN = 3;
а TCSADFLUSH = 4;
а TIOCPKT = 6;
а TIOCPKT_DATA = 0;
а TIOCPKT_FLUSHREAD = 1;
а TIOCPKT_FLUSHWRITE = 2;
а TIOCPKT_STOP = 4;
а TIOCPKT_START = 8;
а TIOCPKT_NOSTOP = 16;
а TIOCPKT_DOSTOP = 32;
а { To be compatible with socket versionа }
а FIONBIO = $8004667e;
а { iflag bitsа }
а IGNBRK = $00001;
а BRKINT = $00002;
а IGNPAR = $00004;
а IMAXBEL = $00008;
а INPCK = $00010;
а ISTRIP = $00020;
а INLCR = $00040;
а IGNCR = $00080;
а ICRNL = $00100;
а IXON = $00400;
а IXOFF = $01000;
а IUCLC = $04000;
а IXANY = $08000;
а PARMRK = $10000;
а { oflag bitsа }
а OPOST = $00001;
а OLCUC = $00002;
а OCRNL = $00004;
а ONLCR = $00008;
а ONOCR = $00010;
а ONLRET = $00020;
а OFILL = $00040;
а CRDLY = $00180;
а CR0 = $00000;
а CR1 = $00080;
а CR2 = $00100;
а CR3 = $00180;
а NLDLY = $00200;
а NL0 = $00000;
а NL1 = $00200;
а BSDLY = $00400;
а BS0 = $00000;
а BS1 = $00400;
а TABDLY = $01800;
а TAB0 = $00000;
а TAB1 = $00800;
а TAB2 = $01000;
а TAB3 = $01800;
а XTABS = $01800;
а VTDLY = $02000;
а VT0 = $00000;
а VT1 = $02000;
а FFDLY = $04000;
а FF0 = $00000;
а FF1 = $04000;
а OFDEL = $08000;
а { cflag bitsа }
а { Baud rate values.а These must fit in speed_t, which is unsigned
а char.а See also the extended baud rates below.а These baud rates
а set an additional bit.а }
а CBAUD = $0100f;
а B0 = $00000;
а B50 = $00001;
а B75 = $00002;
а B110 = $00003;
а B134 = $00004;
а B150 = $00005;
а B200 = $00006;
а B300 = $00007;
а B600 = $00008;
а B1200 = $00009;
а B1800 = $0000a;
а B2400 = $0000b;
а B4800 = $0000c;
а B9600 = $0000d;
а B19200 = $0000e;
а B38400 = $0000f;
а CSIZE = $00030;
а CS5 = $00000;
а CS6 = $00010;
а CS7 = $00020;
а CS8 = $00030;
а CSTOPB = $00040;
а CREAD = $00080;
а PARENB = $00100;
а PARODD = $00200;
а HUPCL = $00400;
а CLOCAL = $00800;
а CBAUDEX = $0100f;
а B57600 = $01001;
ааB115200 = $01002;
а B128000 = $01003;
а B256000 = $01003;
а CRTSXOFF = $04000;
а CRTSCTS = $08000;
а { lflag bitsа }
а ISIG = $0001;
а ICANON = $0002;
а ECHO = $0004;
а ECHOE = $0008;
а ECHOK = $0010;
а ECHONL = $0020;
а NOFLSH = $0040;
а TOSTOP = $0080;
а IEXTEN = $0100;
а FLUSHO = $0200;
а ECHOKE = $0400;
а ECHOCTL = $0800;
а VDISCARD = 1;
а VEOL = 2;
а VEOL2 = 3;
а VEOF = 4;
а VERASE = 5;
а VINTR = 6;
а VKILL = 7;
а VLNEXT = 8;
а VMIN = 9;
а VQUIT = 10;
а VREPRINT = 11;
а VSTART = 12;
а VSTOP = 13;
а VSUSP = 14;
а VSWTC = 15;
а VTIME = 16;
а VWERASE = 17;
а CNUL = 0;
а CDEL = $0007f;
а CESC = byte('\');
а CINTR = byte('C') and $1f;
а CQUIT = $0001c;
а CERASE = byte('H') and $1f;
а CKILL = byte('U') and $1f;
а CEOT = byte('D') and $1f;
а CEOL = 0;
а CEOL2 = 0;
а CEOF = byte('D') and $1f;
а CSTART = byte('Q') and $1f;
а CSTOP = byte('S') and $1f;
а CSWTCH = $0001a;
а NSWTCH = 0;
а CSUSP = byte('Z') and $1f;
а CDSUSP = byte('Y') and $1f;
а CRPRNT = byte('R') and $1f;
а CFLUSH = byte('O') and $1f;
а CWERASE = byte('W') and $1f;
а CLNEXT = byte('V') and $1f;
ааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааа ааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааааа
а
type PFILE=^TFILE;
_IO_marker=record
а next:^_IO_marker;
а sbuf:PFILE;
а _pos:integer;
end;
P_IO_marker=^_IO_marker;
ppchar=^pchar;
pinteger=^integer;
plongint=^longint;
sigset_t=record
а __val:array [0.._SIGSET_NWORDS-1] of longint;
end;
psigset_t=^sigset_t;
__jmp_buf=array [0..5] of longint;
__jmp_buf_tag=record
а __jmpbuf:__jmp_buf;аааааааааааааа (* Calling environment.а *)
а __mask_was_saved:longint;аааааааа (* Saved the signal mask?а *)
а __saved_mask:sigset_t;ааааааааааааа (* Saved signal mask.а *)
end;
jmp_buf=array [0..0] of __jmp_buf_tag;
sigjmp_buf=jmp_buf;
flockrec=record
а l_type:word;аааа (* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK.а *)
а l_whence:word;аа (* Where `l_start' is relative to (like `lseek').а *)
а l_start:longint;ааа (* Offset where the lock begins.а *)
а l_len:longint;ааааа (* Size of the locked area; zero means until EOF.а *)
а l_pid:longint;ааааа (* Process holding the lock.а *)
end;
(* фы шэЄхЁЇхщёр ёюъхЄют *)
in_addr=record
а s_addr:cardinal;
end;
pin_addr=^in_addr;
in_addr_t=cardinal;
(* фы ЁрсюЄv ёю тЁхьхэхь *)
tm=record
а tm_sec:longint;аааааааа (* seconds *)
а tm_min:longint;аааааааа (* minutes *)
а tm_hour:longint;ааааааа (* hours *)
а tm_mday:longint;ааааааа (* day of the month *)
а tm_mon:longint;аааааааа (* month *)
а tm_year:longint;ааааааа (* year *)
а tm_wday:longint;ааааааа (* day of the week *)
а tm_yday:longint;ааааааа (* day in the year *)
а tm_isdst:longint;аааааа (* daylight saving time *)
end;
ptm=^tm;
TFILE=record
а _flags:integer;ааааа (* High-order word is _IO_MAGIC; rest is flags. *)
а (* The following pointers correspond to the C++ streambuf protocol. *)
а (* Note:а Tk uses the _IO_read_ptr and _IO_read_end fields directly. *)
а _IO_read_ptr:pchar;аа (* Current read pointer *)
а _IO_read_end:pchar;аа (* End of get area. *)
а _IO_read_base:pchar;а (* Start of putback+get area. *)
а _IO_write_base:pchar; (* Start of put area. *)
а _IO_write_ptr:pchar;а (* Current put pointer. *)
а _IO_write_end:pchar;а (* End of put area. *)
а _IO_buf_base:pchar;аа (* Start of reserve area. *)
а _IO_buf_end:pchar;ааа (* End of reserve area. *)
а (* The following fields are used to support backing up and undo. *)
а _IO_save_base:pchar; (* Pointer to start of non-current get area. *)
а _IO_backup_base:pchar;а (* Pointer to first valid character of backup area *)
а _IO_save_end:pchar; (* Pointer to end of non-current get area. *)
а _markers:P_IO_marker;
а _chain:^TFILE;
а _fileno:integer;
а _blksize:integer;
а _old_offset:longint; (* This used to be _offset but it's too small.а *)
а _cur_column:word;
а _vtable_offset:byte;
а _shortbuf:array[1..1]of char;
а _lock:pointer;
end;
var
а stdin,stdout:pfile;
function tmpfile:pfile;cdecl;external 'c';
(* Generate a temporary filename.а *)
function tmpnam(__s:pchar):pchar;cdecl;external 'c';
(* Close STREAM.а *)
function fclose(__stream:pfile):integer;cdecl;external 'c';
(* Flush STREAM, or all streams if STREAM is NULL.а *)
function fflush (__stream:pfile):integer;cdecl;external 'c';
(* Close all streams.а *)
function fcloseall:integer;cdecl;external 'c';
(* Open a file and create a new stream for it.а *)
function fopen(fname:pchar;mode:pchar):pfile;cdecl;external 'c';
(* Open a file by fd and create a new stream for it.а *)
function fdopen(fildes:longint;mode:pchar):pfile;cdecl;external 'c';
а
(* Open a file, replacing an existing stream with it. *)
function freopen (_filename:pchar;__modes:pchar;__stream:pfile):pfile;cdecl;external 'c';
(* Create a new stream that refers to a memory buffer.а *)
function fmemopen(__s:pointer;__len:longint;__modes:pchar):pfile;cdecl;external 'c';
(* Open a stream that writes into a malloc'd buffer that is expanded as
аа necessary.а *BUFLOC and *SIZELOC are updated with the buffer's location
аа and the number of characters written on fflush or fclose.а *)
function open_memstream(__bufloc:ppchar;__sizeloc:plongint):pfile;cdecl;external 'c';
(* If BUF is NULL, make STREAM unbuffered.
аа Else make it use buffer BUF, of size BUFSIZ.а *)
procedure setbuf(__stream:pfile;__buf:pchar);cdecl;external 'c';
(* Make STREAM use buffering mode MODE.
аа If BUF is not NULL, use N bytes of it for buffering;
аа else allocate an internal buffer N bytes long.а *)
function setvbuf(__stream:pfile;__buf:pchar;
аааааааааааааааа __modes:longint;__n:longint):integer;cdecl;external 'c';
(* If BUF is NULL, make STREAM unbuffered.
аа Else make it use SIZE bytes of BUF for buffering.а *)
procedure setbuffer(__stream:pfile;__buf:pchar;
аааааааааа ааа __size:longint);cdecl;external 'c';
(* Make STREAM line-buffered.а *)
procedure setlinebuf(__stream:pfile);cdecl;external 'c';
(* Write formatted output to STREAM.а *)
function fprintf(__stream:pfile;fm:pchar;args:array of const):integer;cdecl;external 'c';
(* Write formatted output to stdout.а *)
function printf(fm:pchar;args:array of const):integer;cdecl;external 'c';
(* Write formatted output to S.а *)
function sprintf(__s:pchar;fm:pchar;args:array of const):integer;cdecl;external 'c';
(* Read formatted input from STREAM.а *)
function fscanf(__stream:pfile;fm:pchar;args:array of const):integer;cdecl;external 'c';
(* Read formatted input from stdin.а *)
function scanf(fm:pchar;args:array of const):integer;cdecl;external 'c';
(* Read formatted input from S.а *)
function sscanf(s:pchar;fm:pchar;args:array of const):integer;cdecl;external 'c';
(* Read a character from STREAM.а *)
function fgetc(__stream:pfile):integer;cdecl;external 'c';
function getc(__stream:pfile):integer;cdecl;external 'c';
(* Read a character from stdin.а *)
function getchar:integer;cdecl;external 'c';
(* These are defined in POSIX.1:1996.а *)
function getc_unlocked(__stream:pfile):integer;cdecl;external 'c';
function getchar_unlocked:integer;cdecl;external 'c';
(* Faster version when locking is not necessary.а *)
function fgetc_unlocked(__stream:pfile):integer;cdecl;external 'c';
(* Write a character to STREAM.а *)
function fputc(__c:integer;__stream:pfile):integer;cdecl;external 'c';
function putc(__c:integer;__stream:pfile):integer;cdecl;external 'c';
(* Write a character to stdout.а *)
function putchar(__c:integer):integer;cdecl;external 'c';
(* Faster version when locking is not necessary.а *)
function fputc_unlocked(__c:integer;__stream:pfile):integer;cdecl;external 'c';
(* These are defined in POSIX.1:1996.а *)
function putc_unlocked(__c:integer;__stream:pfile):integer;cdecl;external 'c';
function putchar_unlocked(__c:integer):integer;cdecl;external 'c';
(* Get a word (int) from STREAM.а *)
function getw(__stream:pfile):integer;cdecl;external 'c';
(* Write a word (int) to STREAM.а *)
function putw(__w:integer;__stream:pfile):integer;cdecl;external 'c';
(* Get a newline-terminated string of finite length from STREAM.а *)
function fgets(__s:pchar;__n:integer;__stream:pfile):pchar;cdecl;external 'c';
(* This function does the same as `fgets' but does not lock the stream.а *)
function fgets_unlocked(__s:pchar;__n:integer;__stream:pfile):pchar;cdecl;external 'c';
(* Get a newline-terminated string from stdin, removing the newline.
аа DO NOT USE THIS FUNCTION!!а There is no limit on how much it will read.а *)
function gets(__s:pchar):pchar;cdecl;external 'c';
(* Read up to (and including) a DELIMITER from STREAM into *LINEPTR
аа (and null-terminate it). *LINEPTR is a pointer returned from malloc (or
аа NULL), pointing to *N characters of space.а It is realloc'd as
аа necessary.а Returns the number of characters read (not including the
аа null terminator), or -1 on error or EOF.а *)
function __getdelim(__lineptr:ppchar;__n:plongint;__delimiter:integer;
ааааааааааааааа аааааа __stream:pfile):integer;cdecl;external 'c';
function getdelim(__lineptr:ppchar;__n:plongint;__delimiter:integer;
ааааааааааааааа аааааа __stream:pfile):integer;cdecl;external 'c';
(* Like `getdelim', but reads up to a newline.а *)
function getline(__lineptr:ppchar;__n:plongint;
аааааааааа аааа аааааа __stream:pfile):integer;cdecl;external 'c';
(* Write a string to STREAM.а *)
function fputs(__s:pchar;__stream:pfile):integer;cdecl;external 'c';
(* This function does the same as `fputs' but does not lock the stream.а *)
function fputs_unlocked(__s:pchar;__stream:pfile):integer;cdecl;external 'c';
(* Write a string, followed by a newline, to stdout.а *)
function puts(__s:pchar):integer;cdecl;external 'c';
(* Push a character back onto the input buffer of STREAM.а *)
function ungetc(__c:integer;__stream:pfile):integer;cdecl;external 'c';
(* Read chunks of generic data from STREAM.а *)
function fread(__ptr:pointer;__size, n:longint;
аааааааааа аааа __stream:pfile):longint;cdecl;external 'c';
аааааааааа аааа
(* Write chunks of generic data to STREAM.а *)
function fwrite(__ptr:pointer;__size, n:longint;
аааааааааа аааа __stream:pfile):longint;cdecl;external 'c';
(* Faster versions when locking is not necessary.а *)
function fread_unlocked(__ptr:pointer;__size, n:longint;
аааааааааа аааа __stream:pfile):longint;cdecl;external 'c';
function fwrite_unlocked(__ptr:pointer;__size, n:longint;
аааааааааа аааа __stream:pfile):longint;cdecl;external 'c';
(* Seek to a certain position on STREAM.а *)
function fseek(__stream:pfile;__off:longint;__whence:integer):longint;cdecl;external 'c';
(* Return the current position of STREAM.а *)
function ftell(__stream:pfile):longint;cdecl;external 'c';
(* Rewind to the beginning of STREAM.а *)
procedure rewind(__stream:pfile);cdecl;external 'c';
(* Clear the error and EOF indicators for STREAM.а *)
procedure clearerr(__stream:pfile);cdecl;external 'c';
(* Return the EOF indicator for STREAM.а *)
function feof(__stream:pfile):integer;cdecl;external 'c';
(* Return the error indicator for STREAM.а *)
function ferror(__stream:pfile):integer;cdecl;external 'c';
(* Faster versions when locking is not required.а *)
procedure clearerr_unlocked(__stream:pfile);cdecl;external 'c';
function feof_unlocked(__stream:pfile):integer;cdecl;external 'c';
function ferror_unlocked(__stream:pfile):integer;cdecl;external 'c';
(* Print a message describing the meaning of the value of errno.а *)
procedure perror(__s:pchar);cdecl;external 'c';
(* Return the system file descriptor for STREAM.а *)
function fileno(__stream:pfile):longint;cdecl;external 'c';
(* Faster version when locking is not required.а *)
function fileno_unlocked(__stream:pfile):integer;cdecl;external 'c';
(* Create a new stream connected to a pipe running the given command.а *)
function pipeopen(__command, __modes:pchar):pfile;cdecl;external 'c' name 'popen';
(* Close a stream opened by popen and return the status of its child.а *)
function pipeclose (__stream:pfile):integer;cdecl;external 'c' name 'pclose';
(* Return the name of the controlling terminal.а *)
function ctermid(__s:pchar):pchar;cdecl;external 'c';
(* Return the name of the current user.а *)
function cuserid(__s:pchar):pchar;cdecl;external 'c';
(* Acquire ownership of STREAM.а *)
procedure flockfile(__stream:pfile);cdecl;external 'c';
(* Try to acquire ownership of STREAM but do not block if it is not
аа possible.а *)
function ftrylockfile(__stream:pfile):integer;cdecl;external 'c';
(* Relinquish the ownership granted for STREAM.а *)
procedure funlockfile(__stream:pfile);cdecl;external 'c';
(* ёючфрэшх Їрщыр *)
function fdCreat(PathName:Pchar;mode:longint):longint;cdecl;external 'c' name 'creat';
(* "яхЁхьюЄър" єърчрЄхы эр яхЁтvщ ¤ыхьхэЄ ърЄрыюур *)
procedure rewinddir(dp:pdir);cdecl;external 'c';
(* юцшфрэшх чртхЁ°хэш яЁюЎхёёр *)
function wait(__stat_loc:pinteger):longint;cdecl;external 'c';
(* ЇєэъЎшш фы ёючфрэш эютюую яЁюЎхёёр ё яхЁхьхээvь ўшёыюь ярЁрьхЄЁют *)
function linuxexecl(path:pchar;arg0:pchar;args:array of const):integer;cdecl;external 'c' name 'execl';
function linuxexeclp(filename:pchar;arg0:pchar;args:array of const):integer;cdecl;external 'c' name 'execlp';
(* ЇєэъЎшш фы юяЁхфхыхэш ёюёЄю эш чртхЁ°хэш яЁюЎхёёр *)
function WEXITSTATUS(status:integer):integer;
function WSTOPSIG(status:integer):integer;
function WTERMSIG(status:integer):integer;
function WCOREDUMP(status:integer):boolean;
function WIFEXITED(status:integer):boolean;
function WIFSIGNALED(status:integer):boolean;
function WIFSTOPPED(status:integer):boolean;
(* яЁшюёЄрэртыштрхЄ Єхъє•шщ яЁюЎхёё эр чрфрээюх ъюышўхёЄтю ёхъєэф *)
function sleep(seconds:word):word;cdecl;external 'c';
(* єфры хЄ тёх ёшуэрыv шч эрсюЁр ёшуэрыюта *)
function sigemptyset(__set:psigset_t):integer;cdecl;external 'c';
(* єёЄрэртыштрхЄ тёх ёшуэрыv т эрсюЁх ёшуэрыюта *)
function sigfillset(__set:psigset_t):integer;cdecl;external 'c';
(* фюсрты хЄ ёшуэры SIGNO т эрсюЁ ёшуэрыют *)
function sigaddset(__set:psigset_t;__signo:integer):integer;cdecl;external 'c';
(* єфры хЄ ёшуэры SIGNO шч эрсюЁр ёшуэрыют *)
function sigdelset(__set:psigset_t;__signo:integer):integer;cdecl;external 'c';
(* тючтЁр•рхЄ шёЄшэє, хёыш SIGNO т эрсюЁх, ш ыюц№ т яЁюЄштэюь ёыєўрх *)
function sigismember(__set:psigset_t;__signo:integer):boolean;cdecl;external 'c';
(* тючтЁр•рхЄ шёЄшээюх чэрўхэшх, хёыш эрсюЁ ёшуэрыют эх яєёЄ *)
function sigisemptyset(__set:psigset_t):boolean;cdecl;external 'c';
(* ёючфрхЄ эютvщ эрсюЁ ёшуэрыют шч фтєї тїюфэvї ё яюью•№¦ ыюушўхёъюую "L" *)
function sigandset(__set, __left, __right:psigset_t):integer;cdecl;external 'c';
(* ёючфрхЄ эютvщ эрсюЁ ёшуэрыют шч фтєї тїюфэvї ё яюью•№¦ ыюушўхёъюую "LTL" *)
function sigorset(__set, __left, __right:psigset_t):integer;cdecl;external 'c';
(* эрсюЁ ЇєэъЎшщ фы эхыюъры№эvї яхЁхїюфют *)
(* Store the calling environment in ENV, also saving the signal mask.
аа Return 0.а *)
function setjmp(var __env:jmp_buf):integer;cdecl;external 'c';
(* Store the calling environment in ENV, not saving the signal mask.
аа Return 0.а *)
function _setjmp(var __env:jmp_buf):integer;cdecl;external 'c';
(* Store the calling environment in ENV, also saving the
аа signal mask if SAVEMASK is nonzero.а Return 0.а *)
function sigsetjmp(var __env:jmp_buf;__savemask:longint):integer;cdecl;external 'c' name '__sigsetjmp';
(* Jump to the environment saved in ENV, making the
аа `setjmp' call there return VAL, or 1 if VAL is 0.а *)
procedure longjmp(var __env:jmp_buf;__val:integer);cdecl;external 'c';
(* Jump to the environment saved in ENV, making the
аа sigsetjmp call there return VAL, or 1 if VAL is 0.
аа Restore the signal mask if that sigsetjmp call saved it.
аа This is just an alias `longjmp'.а *)
procedure siglongjmp(var __env:jmp_buf;__val:integer);cdecl;external 'c';
(* fpathconf, pathconf - get configuration values for files *)
function fpathconf(filedes,name:longint):longint;cdecl;external 'c';
function pathconf(path:pchar;name:longint):longint;cdecl;external 'c';
function sysconf(name:integer):longint;cdecl;external 'c';
(* setpgid, getpgid, setpgrp, getpgrp - set/get process group *)
function setpgid(pid, pgid:longint):longint;cdecl;external 'c';
function getpgid(pid:longint):longint;cdecl;external 'c';
function setpgrp:longint;cdecl;external 'c';
function getpgrp:longint;cdecl;external 'c';
function getsid(pid:longint):longint;cdecl;external 'c';
function setsid:longint;cdecl;external 'c';
(* grantpt - grant access to the slave pseudotty*)
function grantpt(fd:longint):longint;cdecl;external 'c';
(* unlockpt - unlock a pseudotty master/slave pair*)
function unlockpt(fd:longint):longint;cdecl;external 'c';
(* ptsname - get the name of the slave pseudotty*)
function ptsname(fd:longint):pchar;cdecl;external 'c';
(* inet_aton() converts the Internet host addressа cpа fromа theа standardааааааааааааааааааааааааааа
аа numbers-and-dotsа notation into binary data and stores it in the structure
аа that inp points to. inet_aton returns nonzero ifа theа addressа isааааааааааааааааааааааааааааааааааааааааа
аа valid, zero if not.*)
function inet_aton(cp:pchar; inp:pin_addr):longint;cdecl;external 'c';
(* Theа inet_addr()а functionа convertsа the Internet host address cp fromааааааа
аа numbers-and-dots notation into binary data in network byteа order.аа Ifаааааааааааааа
аа the input is invalid, INADDR_NONE (usually -1) is returned.а This is anааааааааааааааааааааа
аа obsolete interface to inet_aton, describedа immediatelyа above;а itа isаааааааааааааааааааааааааааа
аа obsolete because -1 is a valid address (255.255.255.255), and inet_atonааааааааааааааааааааааааааааааааааа
аа provides a cleaner way to indicate error return. *)
function inet_addr(cp:pchar):in_addr_t;cdecl;external 'c';
(* The inet_network() function extracts the network numberа inа hostа byte
аа orderа fromа the address cp in numbers-and-dots notation.а If the input
аа is invalid, -1 is returned. *)
function inet_network(cp:pchar):in_addr_t;cdecl;external 'c';
(* The inet_ntoa() function converts the Internet host address in given in
аа networkа byteа order to a string in standard numbers-and-dots notation.
аа The string is returned in a statically allocated buffer,а whichа subse-
аа quent calls will overwrite. *)
function inet_ntoa(n:in_addr):pchar;cdecl;external 'c';
(* Theа inet_makeaddr() function makes an Internet host address in network
аа byte order by combining the network number net with theа localа address
аа host in network net, both in local host byte order. *)
function inet_makeaddr(net, host:longint):in_addr;cdecl;external 'c';
(* Theа inet_lnaof()а functionа returns the local host address part of the
аа Internet address in.а The local host address is returned in localа host
аа byte order. *)
function inet_lnaof(n:in_addr):in_addr_t;cdecl;external 'c';
аааааа
(* The inet_netof() function returns the network number part of the Inter-
аа net Address in.а The network number isа returnedа inа localа hostа byte
аа order. *)
function inet_netof(n:in_addr):in_addr_t;cdecl;external 'c';
ааааааааааа
(* sendto - юЄяЁртшЄ№ ёююс•хэшх т ёюъхЄ.
аа send, sendto, ш sendmsg шёяюы№чє¦Єё фы яхЁхёvыъш ёююс•хэшщ эра фЁєующ
аа ёюъхЄ.ааа sendа ьюцэюа шёяюы№чютрЄ№,а Єюы№ъюа хёыша ёюъхЄа эрїюфшЄё а т
аа ёюхфшэхээюь ёюёЄю эшш, Єюуфр ъръ sendto ш sendmsg ьюцэю шёяюы№чютрЄ№а т
аа ы¦сюх тЁхь . *)
function sendto(sock:longint;var addr;addrlen,flags:longint;
ааааааааааааааа var sato:tsockaddr;tolen:longint):longint;cdecl;external 'c';
ааааааааааааааа
(* recvfrom шёяюы№чєхЄё фы яюыєўхэш ёююс•хэшщ шч ёюъхЄр, ш ьюцхЄ
аа шёяюы№чютрЄ№ё фы яюыєўхэш фрээvї, эхчртшёшью юЄ Єюую, ты хЄё ыш
аа ёюъхЄ юЁшхэЄшЁютрээvь эр ёюхфшэхэш шыш эхЄ. *)
function recvfrom(sock:longint;var addr;addrlen,flags:longint;
ааааааааааааааааа var from:tsockaddr;var fromlen:longint):longint;cdecl;external 'c';
(* character classification routines *)
function isalnum(c:integer):boolean;cdecl;external 'c';
function isalpha(c:integer):boolean;cdecl;external 'c';
function isascii(c:integer):boolean;cdecl;external 'c';
function isblank(c:integer):boolean;cdecl;external 'c';
function iscntrl(c:integer):boolean;cdecl;external 'c';
function isdigit(c:integer):boolean;cdecl;external 'c';
function isgraph(c:integer):boolean;cdecl;external 'c';
function islower(c:integer):boolean;cdecl;external 'c';
function isprint(c:integer):boolean;cdecl;external 'c';
function ispunct(c:integer):boolean;cdecl;external 'c';
function isupper(c:integer):boolean;cdecl;external 'c';
function isxdigit(c:integer):boolean;cdecl;external 'c';
function isspace(c:integer):boolean;
function tolower(c:integer):integer;cdecl;external 'c';
function _tolower(c:integer):integer;cdecl;external 'c';
function toupper(c:integer):integer;cdecl;external 'c';
function _toupper(c:integer):integer;cdecl;external 'c';
function toascii(c:integer):integer;cdecl;external 'c';
(* transform date and time to broken-down time or ASCII *)
(* The ctime(), gmtime() and localtime() functions all take an argument of
аа dataа typeа time_t which represents calendar time.а When interpreted as
аа an absolute time value, it represents theа numberа ofа secondsа elapsed
аа since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). *)
function ctime(var t:longint):pchar;cdecl;external 'c';
function ctime_r(var timep:longint;buf:pchar):pchar;cdecl;external 'c';
function gmtime(var timep:longint):ptm;cdecl;external 'c';
function gmtime_r(var timep:longint; result:ptm):ptm;cdecl;external 'c';
function localtime(var timep:longint):ptm;cdecl;external 'c';
function localtime_r(var timep:longint; result:ptm):ptm;cdecl;external 'c';
(* The asctime() and mktime() functions both take an argument representing
аа broken-down time which is a representation separated into year,а month,
аа day, etc. *)
function asctime(const t:ptm):pchar;cdecl;external 'c';
function asctime_r(const t:ptm;buf:pchar):pchar;cdecl;external 'c';
function mktime(t:ptm):longint;cdecl;external 'c';
function difftime(time1, time2:longint):double;cdecl;external 'c';
(* ЇєэъЎшш фы ЁрсюЄv ё ярь Є№¦ *)
function calloc(nmemb, size:longint):pointer;cdecl;external 'c';
function malloc(size:longint):pointer;cdecl;external 'c';
procedure free(ptr:pointer);cdecl;external 'c';
function realloc(ptr:pointer; size:longint):pointer;cdecl;external 'c';
а
(* ЇєэъЎшш фы ЁрсюЄv ё ърЄрыюурьш *)
function mkdir(pathname:pchar;mode:integer):integer;cdecl;external 'c';
function rmdir(pathname:pchar):integer;cdecl;external 'c';
function chdir(path:pchar):integer;cdecl;external 'c';
function getcwd(name:pchar; size:longint):pchar;cdecl;external 'c';
(* ЁрсюЄр ё сєЇхЁрьш *)
procedure sync;cdecl;external 'c';
function fsync(filedes:integer):integer;cdecl;external 'c';
(* тvяюыэхэшх ъюьрэфv shell'р *)
function runshell(__commandline:pchar):longint;cdecl;external 'c' name 'system';
(* єэшўЄюцхэшх тvчтрт°хую яЁюЎхёёр *)
procedure _exit(status:longint);cdecl;external 'c';
(* шчьхэхэшх шыш Ёрё°шЁхэшх юъЁєцхэш *)
function putenv(str:pchar):longint;cdecl;external 'c';
(* ёьхэр ъюЁэхтюую ърЄрыюур *)
function chroot(path:pchar):longint;cdecl;external 'c';
(* єёЄрэютър Ёхры№эvї ш фхщёЄтє¦•шї шфхэЄшЇшърЄюЁют яюы№чютрЄхы ш уЁєяяv *)
function setuid(uid:longint):longint;cdecl;external 'c';
function setgid(gid:longint):longint;cdecl;external 'c';
(* єчэрЄ№ шыш шчьхэшЄ№ юуЁрэшўхэш яЁюЎхёёр *)
function ulimit(cmd:longint;args:array of const):longint;cdecl;external 'c';
(* ртрЁшщэюх чртхЁ°хэшх яЁюЎхёёр *)
function abort:longint;cdecl;external 'c';
(* ¦юыєўшЄ№ ёъюЁюёЄ№ ттюфр *)
function cfgetispeed(var tdes:TermIOS):longint;cdecl;external 'c';
(* ¦юыєўшЄ№ ёъюЁюёЄ№ тvтюфр *)
function cfgetospeed(var tdes:TermIOS):longint;cdecl;external 'c';
(* шёяюы№чєхЄё фы яюёvыъш ёшуэрыр яЁхЁvтрэш ёхрэёр ёт чш *)
Function tcsendbrk(ttyfd, duration:longint):longint;cdecl;external 'c';
(* ЇєэъЎшш фы ЁрсюЄv ё ярь Є№¦ *)
function memset(buf:pointer; character:longint; size:longint):pointer;cdecl;external 'c';
function memcpy(buf1:pointer; const buf2:pointer; size:longint):pointer;cdecl;external 'c';
function memmove(buf1:pointer; const buf2:pointer; size:longint):pointer;cdecl;external 'c';
function memcmp(const buf1, buf2:pointer; size:longint):longint;cdecl;external 'c';
function memchr(const buf:pointer; character:longint; size:longint):pointer;cdecl;external 'c';
(* ЇєэъЎшш фы ЁрсюЄv ёю ёЄЁюърьш *)
function strpbrk(const s1, s2:pchar):pchar;cdecl;external 'c';
function strspn(const s1, s2:pchar):longint;cdecl;external 'c';
function strcspn(const s1, s2:pchar):longint;cdecl;external 'c';
function strtok(s1:pchar; const s2:pchar):pchar;cdecl;external 'c';
function strtol(const str:pchar; endptr:ppchar; base:longint):longint;cdecl;external 'c';
function atoi(const str:pchar):longint;cdecl;external 'c';
function atol(const str:pchar):longint;cdecl;external 'c';
function strtod(const str:pchar; endptr:ppchar):double;cdecl;external 'c';
function atof(const str:pchar):double;cdecl;external 'c';
ааааааааааааааааааааааааааааааааааа
implementation
(* If WIFEXITED(STATUS), the low-order 8 bits of the status.а *)
function WEXITSTATUS(status:integer):integer;
begin
а WEXITSTATUS:=(status and $ff00) shr 8;
end;
(* If WIFSTOPPED(STATUS), the signal that stopped the child.а *)
function WSTOPSIG(status:integer):integer;
begin
а WSTOPSIG:=WEXITSTATUS(status);
end;
(* If WIFSIGNALED(STATUS), the terminating signal.а *)
function WTERMSIG(status:integer):integer;
begin
а WTERMSIG:=status and $7f;
end;
(* Nonzero if STATUS indicates the child dumped core.а *)
function WCOREDUMP(status:integer):boolean;
begin
а WCOREDUMP:=(status and WCOREFLAG) = 0;
end;
(* Nonzero if STATUS indicates normal termination.а *)
function WIFEXITED(status:integer):boolean;
begin
а WIFEXITED:=(status and $7f) = 0;
end;
(* If WIFSIGNALED(STATUS), the terminating signal.а *)
function WIFSIGNALED(status:integer):boolean;
begin
а WIFSIGNALED:=(not WIFSTOPPED(status)) and (not WIFEXITED(status));
end;
(* Nonzero if STATUS indicates the child is stopped.а *)
function WIFSTOPPED(status:integer):boolean;
begin
а WIFSTOPPED:=(status and $ff) = $7f;
end;
(* test on space character: space, CR, LF, Tab, VTab, FF *)
function isspace(c:integer):boolean;
begin
а isspace:=c in [$9,$20,$a,$b,$c,$d];
end;
begin
а stdin:=fdopen(0,'r');
а stdout:=fdopen(1,'w');
end.
Когда работа над книгой подходила
Когда работа над книгой подходила к концу, была выпущена новая версия компилятора Free Pascal, в котором де-юре зафиксирована возможность использования интерфейса системных вызовов не только в ОС семейства Linux/BSD, но и других клонов UNIX. Для того, чтобы скомпилировать компилятором версии 2.0 программы, представленные в книге, следует заменить в них подключаемый модуль linux на oldlinux. Платформенно-независимая функциональность модуля linux разделена между unix, unixtype, baseunix и unixutil. В модуль X86 вынесены части, специфичные для X86-архитектуры.
Для удобства перехода на новую версию компилятора приводим таблицу соответствия модулей в разных версиях компилятора.
а) константы:
Название (1.x) |
Описание |
Название (2.x) |
Модуль |
Maximum number of arguments to a program. |
ARG_MAX |
unix, baseunix, unixtype |
|
Number of bits in a word. |
BITSINWORD |
baseunix |
|
CLONE_FILES |
Clone option: open files shared between processes |
CLONE_FILES |
linux |
CLONE_FS |
Clone option: fs info shared between processes |
CLONE_FS |
linux |
CLONE_PID |
Clone option: PID shared between processes |
CLONE_PID |
linux |
CLONE_SIGHAND |
Clone option: signal handlers shared between processes |
CLONE_SIGHAND |
linux |
CLONE_VM |
Clone option: VM shared between processes |
CLONE_VM |
linux |
CSIGNAL |
Clone option: Signal mask to be sent at exit |
CSIGNAL |
linux |
System error: Argument list too long |
ESysE2BIG |
baseunix |
|
System error: Permission denied |
ESysEACCES |
baseunix |
|
System error: Address already in use |
ESysEADDRINUSE |
baseunix |
|
System error: Cannot assign requested address |
ESysEADDRNOTAVAIL |
baseunix |
|
System error: Advertise error |
ESysEADV |
baseunix |
|
System error: Address family not supported by protocol |
ESysEAFNOSUPPORT |
baseunix |
|
System error: Try again |
ESysEAGAIN |
baseunix |
|
System error: Operation already in progress |
ESysEALREADY |
baseunix |
|
System error: Invalid exchange |
ESysEBADE |
baseunix |
|
System error: Bad file number |
ESysEBADF |
baseunix |
|
System error: File descriptor in bad state |
ESysEBADFD |
baseunix |
|
System error: Not a data message |
ESysEBADMSG |
baseunix |
|
System error: Invalid request descriptor |
ESysEBADR |
baseunix |
|
System error: Invalid request code |
ESysEBADRQC |
baseunix |
|
System error: Invalid slot |
ESysEBADSLT |
baseunix |
|
System error: Bad font file format |
ESysEBFONT |
baseunix |
|
System error: Device or resource busy |
ESysEBUSY |
baseunix |
|
System error: No child processes |
ESysECHILD |
baseunix |
|
System error: Channel number out of range |
ESysECHRNG |
baseunix |
|
System error: Communication error on send |
ESysECOMM |
baseunix |
|
System error: Software caused connection abort |
ESysECONNABORTED |
baseunix |
|
System error: Connection refused |
ESysECONNREFUSED |
baseunix |
|
System error: Connection reset by peer |
ESysECONNRESET |
baseunix |
|
System error: Resource deadlock would occur |
ESysEDEADLK |
baseunix |
|
System error: File locking deadlock error |
ESysEDEADLOCK |
baseunix |
|
System error: Destination address required |
ESysEDESTADDRREQ |
baseunix |
|
System error: Math argument out of domain of func |
ESysEDOM |
baseunix |
|
System error: RFS specific error |
ESysEDOTDOT |
baseunix |
|
System error: Quota exceeded |
ESysEDQUOT |
baseunix |
|
System error: File exists |
ESysEEXIST |
baseunix |
|
System error: Bad address |
ESysEFAULT |
baseunix |
|
System error: File too large |
ESysEFBIG |
baseunix |
|
System error: Host is down |
ESysEHOSTDOWN |
baseunix |
|
System error: No route to host |
ESysEHOSTUNREACH |
baseunix |
|
System error: Identifier removed |
ESysEIDRM |
baseunix |
|
System error: Illegal byte sequence |
ESysEILSEQ |
baseunix |
|
System error: Operation now in progress |
ESysEINPROGRESS |
baseunix |
|
System error: Interrupted system call |
ESysEINTR |
baseunix |
|
System error: Invalid argument |
ESysEINVAL |
baseunix |
|
System error: I/O error |
ESysEIO |
baseunix |
|
System error: Transport endpoint is already connected |
ESysEISCONN |
baseunix |
|
System error: Is a directory |
ESysEISDIR |
baseunix |
|
System error: Is a named type file |
ESysEISNAM |
baseunix |
|
System error: Level 2 halted |
ESysEL2HLT |
baseunix |
|
System error: Level 2 not synchronized |
ESysEL2NSYNC |
baseunix |
|
System error: Level 3 halted |
ESysEL3HLT |
baseunix |
|
System error: Level 3 reset |
ESysEL3RST |
baseunix |
|
System error: Can not access a needed shared library |
ESysELIBACC |
baseunix |
|
System error: Accessing a corrupted shared library |
ESysELIBBAD |
baseunix |
|
System error: Cannot exec a shared library directly |
ESysELIBEXEC |
baseunix |
|
System error: Attempting to link in too many shared libraries |
ESysELIBMAX |
baseunix |
|
System error: .lib section in a.out corrupted |
ESysELIBSCN |
baseunix |
|
System error: Link number out of range |
ESysELNRNG |
baseunix |
|
System error: Too many symbolic links encountered |
ESysELOOP |
baseunix |
|
System error: Too many open files |
ESysEMFILE |
baseunix |
|
System error: Too many links |
ESysEMLINK |
baseunix |
|
System error: Message too long |
ESysEMSGSIZE |
baseunix |
|
System error: Multihop attempted |
ESysEMULTIHOP |
baseunix |
|
System error: File name too long |
ESysENAMETOOLONG |
baseunix |
|
System error: No XENIX semaphores available |
ESysENAVAIL |
baseunix |
|
System error: Network is down |
ESysENETDOWN |
baseunix |
|
System error: Network dropped connection because of reset |
ESysENETRESET |
baseunix |
|
System error: Network is unreachable |
ESysENETUNREACH |
baseunix |
|
System error: File table overflow |
ESysENFILE |
baseunix |
|
System error: No anode |
ESysENOANO |
baseunix |
|
System error: No buffer space available |
ESysENOBUFS |
baseunix |
|
System error: No CSI structure available |
ESysENOCSI |
baseunix |
|
System error: No data available |
ESysENODATA |
baseunix |
|
System error: No such device |
ESysENODEV |
baseunix |
|
System error: No such file or directory |
ESysENOENT |
baseunix |
|
System error: Exec format error |
ESysENOEXEC |
baseunix |
|
System error: No record locks available |
ESysENOLCK |
baseunix |
|
System error: Link has been severed |
ESysENOLINK |
baseunix |
|
System error: Out of memory |
ESysENOMEM |
baseunix |
|
System error: No message of desired type |
ESysENOMSG |
baseunix |
|
System error: Machine is not on the network |
ESysENONET |
baseunix |
|
System error: Package not installed |
ESysENOPKG |
baseunix |
|
System error: Protocol not available |
ESysENOPROTOOPT |
baseunix |
|
System error: No space left on device |
ESysENOSPC |
baseunix |
|
System error: Out of streams resources |
ESysENOSR |
baseunix |
|
System error: Device not a stream |
ESysENOSTR |
baseunix |
|
System error: Function not implemented |
ESysENOSYS |
baseunix |
|
System error: Block device required |
ESysENOTBLK |
baseunix |
|
System error: Transport endpoint is not connected |
ESysENOTCONN |
baseunix |
|
System error: Not a directory |
ESysENOTDIR |
baseunix |
|
System error: Directory not empty |
ESysENOTEMPTY |
baseunix |
|
System error: Not a XENIX named type file |
ESysENOTNAM |
||
System error: Socket operation on non-socket |
ESysENOTSOCK |
baseunix |
|
System error: Not a typewriter |
ESysENOTTY |
baseunix |
|
System error: Name not unique on network |
ESysENOTUNIQ |
baseunix |
|
System error: No such device or address |
ESysENXIO |
baseunix |
|
System error: Operation not supported on transport endpoint |
ESysEOPNOTSUPP |
||
System error: Value too large for defined data type |
ESysEOVERFLOW |
baseunix |
|
System error: Operation not permitted. |
ESysEPERM |
baseunix |
|
System error: Protocol family not supported |
ESysEPFNOSUPPORT |
baseunix |
|
System error: Broken pipe |
ESysEPIPE |
baseunix |
|
System error: Protocol error |
ESysEPROTO |
baseunix |
|
System error: Protocol not supported |
ESysEPROTONOSUPPORT |
baseunix |
|
System error: Protocol wrong type for socket |
ESysEPROTOTYPE |
baseunix |
|
System error: Math result not representable |
ESysERANGE |
baseunix |
|
System error: Remote address changed |
ESysEREMCHG |
baseunix |
|
System error: Object is remote |
ESysEREMOTE |
baseunix |
|
System error: Remote I/O error |
ESysEREMOTEIO |
baseunix |
|
System error: Interrupted system call should be restarted |
ESysERESTART |
baseunix |
|
System error: Read-only file system |
ESysEROFS |
baseunix |
|
System error: Cannot send after transport endpoint shutdown |
ESysESHUTDOWN |
baseunix |
|
System error: Socket type not supported |
ESysESOCKTNOSUPPORT |
baseunix |
|
System error: Illegal seek |
ESysESPIPE |
baseunix |
|
System error: No such process |
ESysESRCH |
baseunix |
|
System error: Srmount error |
ESysESRMNT |
baseunix |
|
System error: Stale NFS file handle |
ESysESTALE |
baseunix |
|
System error: Streams pipe error |
ESysESTRPIPE |
baseunix |
|
System error: Timer expired |
ESysETIME |
baseunix |
|
System error: Connection timed out |
ESysETIMEDOUT |
baseunix |
|
System error: Too many references: cannot splice |
ESysETOOMANYREFS |
baseunix |
|
System error: Text (code segment) file busy |
ESysETXTBSY |
baseunix |
|
System error: Structure needs cleaning |
ESysEUCLEAN |
baseunix |
|
System error: Protocol driver not attached |
ESysEUNATCH |
baseunix |
|
System error: Too many users |
ESysEUSERS |
baseunix |
|
System error: Operation would block |
ESysEWOULDBLOCK |
baseunix |
|
System error: Cross-device link |
ESysEXDEV |
baseunix |
|
System error: Exchange full |
ESysEXFULL |
baseunix |
|
Maximum elements in a TFDSet array. |
FD_MAXFDSET |
baseunix |
|
fs_ext |
File system type (FSStat): (ext) Extended |
fs_ext |
unix |
fs_ext2 |
File system type (FSStat): (ext2) Second extended |
fs_ext2 |
unix |
fs_iso |
File system type (FSStat): ISO 9660 |
fs_iso |
unix |
fs_minix |
File system type (FSStat): Minix |
fs_minix |
unix |
fs_minix_30 |
File system type (FSStat): Minix 3.0 |
fs_minix_30 |
unix |
fs_minux_V2 |
File system type (FSStat): Minix V2 |
fs_minux_V2 |
unix |
fs_msdos |
File system type (FSStat): MSDOS (FAT) |
fs_msdos |
unix |
fs_nfs |
File system type (FSStat): NFS |
fs_nfs |
unix |
fs_old_ext2 |
File system type (FSStat): (ext2) Old second extended |
fs_old_ext2 |
unix |
fs_proc |
File system type (FSStat): PROC fs |
fs_proc |
unix |
fs_xia |
File system type (FSStat): XIA |
fs_xia |
unix |
F_GetFd |
fpFCntl command: Get close-on-exec flag |
F_GetFd |
baseunix |
F_GetFl |
fpFCntl command: Get filedescriptor flags |
F_GetFl |
baseunix |
F_GetLk |
fpFCntl command: Get lock |
F_GetLk |
baseunix |
F_GetOwn |
fpFCntl command: get owner of filedescriptor events |
F_GetOwn |
baseunix |
F_OK |
fpAccess call test: file exists. |
F_OK |
baseunix |
F_SetFd |
fpFCntl command: Set close-on-exec flag |
F_SetFd |
baseunix |
F_SetFl |
fpFCntl command: Set filedescriptor flags |
F_SetFl |
baseunix |
F_SetLk |
fpFCntl command: Set lock |
F_SetLk |
baseunix |
F_SetLkW |
fpFCntl command: Test lock |
F_SetLkW |
baseunix |
F_SetOwn |
FCntl command: Set owner of filedescriptor events F_SetOwn |
baseunix |
|
IOCtl_TCGETS |
IOCTL call number: get Terminal Control settings |
IOCtl_TCGETS |
unix |
Last bit in word. |
ln2bitmask |
baseunix |
|
Power of 2 number of bits in word. |
ln2bitsinword |
baseunix |
|
LOCK_EX |
FLock Exclusive lock |
LOCK_EX |
unix |
LOCK_NB |
FLock Non-blocking operation |
LOCK_NB |
unix |
LOCK_SH |
FLock Shared lock |
LOCK_SH |
unix |
LOCK_UN |
FLock unlock |
LOCK_UN |
unix |
MAP_ANONYMOUS |
fpMMap map type: Don't use a file |
MAP_ANONYMOUS |
baseunix |
MAP_DENYWRITE |
MMap option: Ignored. |
MAP_DENYWRITE |
unix |
MAP_EXECUTABLE |
MMap option: Ignored. |
MAP_EXECUTABLE |
unix |
MAP_FIXED |
MMap map type: Interpret addr exactly |
MAP_FIXED |
unix |
MAP_GROWSDOWN |
MMap option: Memory grows downward (like a stack) |
MAP_GROWSDOWN |
unix |
MAP_LOCKED |
MMap option: lock the pages in memory. |
MAP_LOCKED |
unix |
MAP_NORESERVE |
MMap option: Do not reserve swap pages for this memory. |
MAP_NORESERVE |
unix |
MAP_PRIVATE |
MMap map type: Changes are private |
MAP_PRIVATE |
unix, baseunix |
MAP_SHARED |
MMap map type: Share changes |
MAP_SHARED |
unix |
MAP_TYPE |
MMap map type: Bitmask for type of mapping |
MAP_TYPE |
unix |
MINSIGSTKSZ |
NCC: Number of control characters in termio record. |
||
Maximum filename length. |
NAME_MAX |
unix, unixtype, baseunix |
|
NCCS |
Number of control characters in termios record. |
||
fpOpen file open mode: Append to file |
O_APPEND |
baseunix |
|
fpOpen file open mode: Create if file does not yet exist. |
O_CREAT |
baseunix |
|
fpOpen file open mode: Minimize caching effects |
O_DIRECT |
baseunix |
|
fpOpen file open mode: File must be directory. |
O_DIRECTORY |
baseunix |
|
fpOpen file open mode: Open exclusively |
O_EXCL |
baseunix |
|
fpOpen file open mode: Open for 64-bit I/O |
O_LARGEFILE |
baseunix |
|
fpOpen file open mode: Alias for O_NonBlock |
O_NDELAY |
baseunix |
|
fpOpen file open mode: No TTY control. |
O_NOCTTY |
baseunix |
|
fpOpen file open mode: Fail if file is symbolic link. |
O_NOFOLLOW |
baseunix |
|
fpOpen file open mode: Open in non-blocking mode |
O_NONBLOCK |
baseunix |
|
fpOpen file open mode: Read only |
O_RDONLY |
baseunix |
|
fpOpen file open mode: Read/Write |
O_RDWR |
baseunix |
|
fpOpen file open mode: Write to disc at once |
O_SYNC |
baseunix |
|
fpOpen file open mode: Truncate file to length 0 |
O_TRUNC |
baseunix |
|
fpOpen file open mode: Write only |
O_WRONLY |
baseunix |
|
Open_Accmode |
Bitmask to determine access mode in open flags. |
Open_Accmode |
unix |
Open_Append |
File open mode: Append to file |
Open_Append |
unix |
Open_Creat |
File open mode: Create if file does not yet exist. |
Open_Creat |
unix |
Open_Direct |
File open mode: Minimize caching effects |
Open_Direct |
unix |
Open_Directory |
File open mode: File must be directory. |
Open_Directory |
unix |
Open_Excl |
File open mode: Open exclusively |
Open_Excl |
unix |
Open_LargeFile |
File open mode: Open for 64-bit I/O |
Open_LargeFile |
unix |
Open_NDelay |
File open mode: Alias for Open_NonBlock |
Open_NDelay |
unix |
Open_NoCtty |
File open mode: No TTY control. |
Open_NoCtty |
unix |
Open_NoFollow |
File open mode: Fail if file is symbolic link. |
Open_NoFollow |
unix |
Open_NonBlock |
File open mode: Open in non-blocking mode |
Open_NonBlock |
unix |
Open_RdOnly |
File open mode: Read only |
Open_RdOnly |
unix |
Open_RdWr |
File open mode: Read/Write |
Open_RdWr |
unix |
Open_Sync |
File open mode: Write to disc at once |
Open_Sync |
unix |
Open_Trunc |
File open mode: Truncate file to length 0 |
Open_Trunc |
unix |
Open_WrOnly |
File open mode: Write only |
Open_WrOnly |
unix |
Maximum pathname length. |
PATH_MAX |
unix, unixtype, baseunix |
|
Prio_PGrp |
Get/set process group priority |
Prio_PGrp |
unixtype |
Prio_Process |
Get/Set process priority |
Prio_Process |
unixtype |
Prio_User |
Get/set user priority |
Prio_User |
unixtype |
PROT_EXEC |
FpMMap memory access: page can be executed |
PROT_EXEC |
unix |
PROT_NONE |
FpMMap memory access: page can not be accessed |
PROT_NONE |
unix |
PROT_READ |
FpMMap memory access: page can be read |
PROT_READ |
unix |
PROT_WRITE |
FpMMap memory access: page can be written |
PROT_WRITE |
unix |
P_IN |
Input file descriptor of pipe pair. |
P_IN |
unix |
P_OUT |
Output file descriptor of pipe pair. |
P_OUT |
unix |
R_OK |
fpAccess call test: read allowed |
R_OK |
baseunix |
SA_INTERRUPT |
Sigaction options: ? |
SA_INTERRUPT |
baseunix |
SA_NOCLDSTOP |
Sigaction options: Do not receive notification when child processes stop |
SA_NOCLDSTOP |
baseunix |
Sigaction options: ? |
SA_NOCLDWAIT |
baseunix |
|
SA_NOMASK |
Sigaction options: Do not prevent the signal from being received when it is handled. |
SA_NOMASK |
baseunix |
SA_ONESHOT |
Sigaction options: Restore the signal action to the default state. |
SA_ONESHOT |
baseunix |
SA_ONSTACK |
Socket option |
||
SA_RESTART |
Sigaction options: Provide behaviour compatible with BSD signal semantics |
SA_RESTART |
baseunix |
SA_SHIRQ |
Sigaction options: ? |
SA_SHIRQ |
baseunix |
Sigaction options: The signal handler takes 3 arguments, not one. |
SA_SIGINFO |
baseunix |
|
SA_STACK |
Sigaction options: Call the signal handler on an alternate signal stack. |
SA_STACK |
baseunix |
Seek_Cur |
fpLSeek option: Set position relative to current position. |
Seek_Cur |
baseunix |
Seek_End |
fpLSeek option: Set position relative to end of file. |
Seek_End |
baseunix |
Seek_Set |
fpLSeek option: Set absolute position. |
Seek_Set |
baseunix |
SIGABRT |
Signal: ABRT (Abort) |
SIGABRT |
baseunix |
SIGALRM |
Signal: ALRM (Alarm clock) |
SIGALRM |
baseunix |
SIGBUS |
Signal: BUS (bus error) |
SIGBUS |
baseunix |
SIGCHLD |
Signal: CHLD (child status changed) |
SIGCHLD |
baseunix |
SIGCONT |
Signal: CONT (Continue) |
SIGCONT |
baseunix |
SIGFPE |
Signal: FPE (Floating point error) |
SIGFPE |
baseunix |
SIGHUP |
Signal: HUP (Hangup) |
SIGHUP |
baseunix |
SIGILL |
Signal: ILL (Illegal instruction) |
SIGILL |
baseunix |
SIGINT |
Signal: INT (Interrupt) |
SIGINT |
baseunix |
SIGIO |
Signal: IO (I/O operation possible) |
SIGIO |
baseunix |
SIGIOT |
Signal: IOT (IOT trap) |
SIGIOT |
baseunix |
SIGKILL |
Signal: KILL (unblockable) |
SIGKILL |
baseunix |
SIGPIPE |
Signal: PIPE (Broken pipe |
SIGPIPE |
baseunix |
SIGPOLL |
Signal: POLL (Pollable event) |
SIGPOLL |
baseunix |
SIGPROF |
Signal: PROF (Profiling alarm) |
SIGPROF |
baseunix |
SIGPWR |
Signal: PWR (power failure restart) |
SIGPWR |
baseunix |
SIGQUIT |
Signal: QUIT |
SIGQUIT |
baseunix |
SIGSEGV |
Signal: SEGV (Segmentation violation) |
SIGSEGV |
baseunix |
SIGSTKFLT |
Signal: STKFLT (Stack Fault) |
SIGSTKFLT |
baseunix |
SIGSTKSZ |
Signal Stack size error |
SIGSTKSZ |
baseunix |
SIGSTOP |
Signal: STOP (Stop, unblockable) |
SIGSTOP |
baseunix |
SIGTerm |
Signal: TERM (Terminate) |
SIGTerm |
baseunix |
SIGTRAP |
Signal: TRAP (Trace trap) |
SIGTRAP |
baseunix |
SIGTSTP |
Signal: TSTP (keyboard stop) |
SIGTSTP |
baseunix |
SIGTTIN |
Signal: TTIN (Terminal input, background) |
SIGTTIN |
baseunix |
SIGTTOU |
Signal: TTOU (Terminal output, background) |
SIGTTOU |
baseunix |
SIGUNUSED |
Signal: Unused |
SIGUNUSED |
baseunix |
SIGURG |
Signal: URG (Socket urgent condition) |
SIGURG |
baseunix |
SIGUSR1 |
Signal: USR1 (User-defined signal 1) |
SIGUSR1 |
baseunix |
SIGUSR2 |
Signal: USR2 (User-defined signal 2) |
SIGUSR2 |
baseunix |
SIGVTALRM |
Signal: VTALRM (Virtual alarm clock) |
SIGVTALRM |
baseunix |
SIGWINCH |
Signal: WINCH (Window/Terminal size change) |
SIGWINCH |
baseunix |
SIGXCPU |
Signal: XCPU (CPU limit exceeded) |
SIGXCPU |
baseunix |
SIGXFSZ |
Signal: XFSZ (File size limit exceeded) |
SIGXFSZ |
baseunix |
SIG_BLOCK |
Sigprocmask flags: Add signals to the set of blocked signals. |
SIG_BLOCK |
baseunix |
SIG_DFL |
Signal handler: Default signal handler |
SIG_DFL |
baseunix |
SIG_ERR |
Signal handler: error |
SIG_ERR |
baseunix |
SIG_IGN |
Signal handler: Ignore signal |
SIG_IGN |
baseunix |
Maximum system signal number. |
SIG_MAXSIG |
unix, unixtype, baseunix |
|
SIG_SETMASK |
Sigprocmask flags: Set of blocked signals is given. |
SIG_SETMASK |
baseunix |
SIG_UNBLOCK |
Sigprocmask flags: Remove signals from the set set of blocked signals. |
SIG_UNBLOCK |
baseunix |
SI_PAD_SIZE |
Signal information record pad bytes size. Do not use. |
SI_PAD_SIZE |
baseunix |
SS_DISABLE |
Socket options |
||
SS_ONSTACK |
Socket options |
||
STAT_IFBLK |
File (stat record) mode: Block device |
STAT_IFBLK |
unix |
STAT_IFCHR |
File (stat record) mode: Character device |
STAT_IFCHR |
unix |
STAT_IFDIR |
File (stat record) mode: Directory |
STAT_IFDIR |
unix |
STAT_IFIFO |
File (stat record) mode: FIFO |
STAT_IFIFO |
unix |
STAT_IFLNK |
File (stat record) mode: Link |
STAT_IFLNK |
unix |
STAT_IFMT |
File (stat record) mode: File type bit mask |
STAT_IFMT |
unix |
STAT_IFREG |
File (stat record) mode: Regular file |
STAT_IFREG |
unix |
STAT_IFSOCK |
File (stat record) mode: Socket |
STAT_IFSOCK |
unix |
STAT_IRGRP |
File (stat record) mode: Group read permission |
STAT_IRGRP |
unix |
STAT_IROTH |
File (stat record) mode: Other read permission |
STAT_IROTH |
unix |
STAT_IRUSR |
File (stat record) mode: Owner read permission |
STAT_IRUSR |
unix |
STAT_IRWXG |
File (stat record) mode: Group permission bits mask |
STAT_IRWXG |
unix |
STAT_IRWXO |
File (stat record) mode: Other permission bits mask |
STAT_IRWXO |
unix |
STAT_IRWXU |
File (stat record) mode: Owner permission bits mask |
STAT_IRWXU |
unix |
STAT_ISGID |
File (stat record) mode: GID bit set |
STAT_ISGID |
unix |
STAT_ISUID |
File (stat record) mode: UID bit set |
STAT_ISUID |
unix |
STAT_ISVTX |
File (stat record) mode: Sticky bit set |
STAT_ISVTX |
unix |
STAT_IWGRP |
File (stat record) mode: Group write permission |
STAT_IWGRP |
unix |
STAT_IWOTH |
File (stat record) mode: Other write permission |
STAT_IWOTH |
unix |
STAT_IWUSR |
File (stat record) mode: Owner write permission |
STAT_IWUSR |
unix |
STAT_IXGRP |
File (stat record) mode: Others execute permission |
STAT_IXGRP |
unix |
STAT_IXOTH |
File (stat record) mode: Others execute permission |
STAT_IXOTH |
unix |
STAT_IXUSR |
File (stat record) mode: Others execute permission |
STAT_IXUSR |
unix |
Max system name length. |
SYS_NMLN |
unix, unixtype, baseunix |
|
File mode: Block device |
S_IFBLK |
baseunix |
|
File mode: Character device |
S_IFCHR |
baseunix |
|
File mode: Directory |
S_IFDIR |
baseunix |
|
File mode: FIFO |
S_IFIFO |
baseunix |
|
File mode: Link |
S_IFLNK |
baseunix |
|
File mode: File type bit mask |
S_IFMT |
baseunix |
|
File mode: Regular file |
S_IFREG |
baseunix |
|
File mode: Socket |
S_IFSOCK |
baseunix |
|
Mode flag: Read by group. |
S_IRGRP |
baseunix |
|
Mode flag: Read by others. |
S_IROTH |
baseunix |
|
Mode flag: Read by owner. |
S_IRUSR |
baseunix |
|
Mode flag: Write by group. |
S_IWGRP |
baseunix |
|
Mode flag: Write by others. |
S_IWOTH |
baseunix |
|
Mode flag: Write by owner. |
S_IWUSR |
baseunix |
|
Mode flag: Execute by group. |
S_IXGRP |
baseunix |
|
Mode flag: Execute by others. |
S_IXOTH |
baseunix |
|
Mode flag: Execute by owner. |
S_IXUSR |
baseunix |
|
Max length of utsname domain name. |
UTSNAME_DOMAIN_LENGTH |
baseunix |
|
Max length of utsname system name, release, version, machine. |
UTSNAME_LENGTH |
baseunix |
|
Max length of utsname node name. |
UTSNAME_NODENAME_LENGTH |
baseunix |
|
Wait_Any |
WaitPID: Wait on any process |
Wait_Any |
unix |
Wait_Clone |
WaitPID: Wait on clone processes only. |
Wait_MyPGRP |
unix |
Wait_MyPGRP |
WaitPID: Wait processes from current process group |
Wait_MyPGRP |
unix |
Wait_NoHang |
WaitPID: Do not wait |
Wait_NoHang |
unix |
Wait_UnTraced |
WaitPID: Also report stopped but untraced processes |
Wait_UnTraced |
unix |
WNOHANG |
Waitpid option: Do not wait for processes to terminate. |
WNOHANG |
baseunix |
Number of words in a TFDSet array |
wordsinfdset |
baseunix |
|
Number of words in a signal set. |
wordsinsigset |
baseunix |
|
WUNTRACED |
Waitpid option: Also report children wich were stopped but not yet reported |
WUNTRACED |
baseunix |
W_OK |
fpAccess call test: write allowed |
W_OK |
baseunix |
X_OK |
fpAccess call test: execute allowed |
X_OK |
baseunix |
Mutex options: |
_PTHREAD_MUTEX_ADAPTIVE_NP |
unixtype |
|
Mutex options: |
_PTHREAD_MUTEX_DEFAULT |
unixtype |
|
Mutex options: |
_PTHREAD_MUTEX_ERRORCHECK |
unixtype |
|
Mutex options: double lock returns an error code. |
_PTHREAD_MUTEX_ERRORCHECK_NP |
unixtype |
|
Mutex options: Fast mutex |
_PTHREAD_MUTEX_FAST_NP |
unixtype |
|
Mutex options: |
_PTHREAD_MUTEX_NORMAL |
unixtype |
|
Mutex options: |
_PTHREAD_MUTEX_RECURSIVE |
unixtype |
|
Mutex options: recursive mutex |
_PTHREAD_MUTEX_RECURSIVE_NP |
unixtype |
|
Mutex options: ? |
_PTHREAD_MUTEX_TIMED_NP |
unixtype |
|
__WCLONE |
Waitpid option: Wait for clone children only |
б) типы данных:
Название (1.x) |
Описание |
Название (2.x) |
Модуль |
Block count type. |
Blkcnt_t |
baseunix |
|
Block size type. |
Blksize_t |
baseunix |
|
C type: 8-bit signed integer |
cchar |
unix, baseunix, unixtype |
|
Double precision real format. |
cDouble |
unix, baseunix, unixtype |
|
Floating-point real format |
cFloat |
unix, baseunix, unixtype |
|
C type: integer (natural size) |
cInt |
unix, baseunix, unixtype |
|
C type: 16 bits sized, signed integer. |
cInt16 |
unix, baseunix, unixtype |
|
C type: 32 bits sized, signed integer. |
cInt32 |
unix, baseunix, unixtype |
|
C type: 64 bits sized, signed integer. |
cInt64 |
unix, baseunix, unixtype |
|
C type: 8 bits sized, signed integer. |
cInt8 |
unix, baseunix, unixtype |
|
Long double precision real format (Extended) |
clDouble |
unix, baseunix, unixtype |
|
Clock ticks type |
clock_t |
unix, baseunix, unixtype |
|
C type: long signed integer (double sized) |
cLong |
unix, baseunix, unixtype |
|
C type: 64-bit (double long) signed integer. |
clonglong |
unix, baseunix, unixtype |
|
C type: short signed integer (half sized) |
cshort |
unix, baseunix, unixtype |
|
C type: 8-bit unsigned integer |
cuchar |
unix, baseunix, unixtype |
|
C type: unsigned integer (natural size) |
cUInt |
unix, baseunix, unixtype |
|
C type: 16 bits sized, unsigned integer. |
cUInt16 |
unix, baseunix, unixtype |
|
C type: 32 bits sized, unsigned integer. |
cUInt32 |
unix, baseunix, unixtype |
|
C type: 64 bits sized, unsigned integer. |
cUInt64 |
unix, baseunix, unixtype |
|
C type: 8 bits sized, unsigned integer. |
cUInt8 |
unix, baseunix, unixtype |
|
C type: long unsigned integer (double sized) |
cuLong |
unix, baseunix, unixtype |
|
C type: 64-bit (double long) unsigned integer. |
culonglong |
unix, baseunix, unixtype |
|
Alias for cuint |
cunsigned |
unix, baseunix, unixtype |
|
C type: short unsigned integer (half sized) |
cushort |
unix, baseunix, unixtype |
|
ComStr |
Command-line string type. |
ComStr |
unixutil |
dev_t |
Device descriptor type |
dev_t |
unix, baseunix, unixtype |
Record used in fpOpenDir and fpReadDir calls |
Dir |
baseunix |
|
dirent |
Record used in the fpReadDir function to return files in a directory. |
dirent |
baseunix |
DirStr |
Filename directory part string type. |
DirStr |
unixutil |
ExtStr |
Filename extension part string type. |
ExtStr |
unixutil |
fdSet |
Array containing file descriptor bitmask for the Select call. |
||
Lock description type for fpFCntl lock call. |
FLock |
baseunix |
|
Group ID type. |
gid_t |
unix, baseunix, unixtype |
|
64-bit inode type. |
ino64_t |
baseunix |
|
Inode type. |
ino_t |
unix, baseunix, unixtype |
|
Kernel device type |
kDev_t |
unixtype |
|
Inode mode type. |
mode_t |
unix, baseunix, unixtype |
|
NameStr |
Filename name part string type. |
NameStr |
unixutil |
Number of links type. |
nlink_t |
unix, baseunix, unixtype |
|
64-bit offset type. |
off64_t |
baseunix |
|
Offset type. |
off_t |
unix, baseunix |
|
PathStr |
Filename path part string type. |
PathStr |
unixutil |
pointer to TBlkCnt type. |
PBlkCnt |
baseunix |
|
Pointer to TBlkSize type. |
PBlkSize |
baseunix |
|
Alias for cchar |
pcchar |
unix, baseunix, unixtype |
|
Pointer to cdouble type. |
pcDouble |
unix, baseunix, unixtype |
|
Pointer to cfloat type. |
pcFloat |
unix, baseunix, unixtype |
|
Pointer to cInt type. |
pcInt |
unix, baseunix, unixtype |
|
Pointer to cldouble type. |
pclDouble |
unix, baseunix, unixtype |
|
Pointer to TClock type. |
pClock |
unix, baseunix, unixtype, unixtype |
|
Pointer to cLong type. |
pcLong |
unix, baseunix, unixtype |
|
Pointer to cShort type. |
pcshort |
unix, baseunix, unixtype |
|
Alias for cuchar |
pcuchar |
unix, baseunix, unixtype |
|
Pointer to cUInt type. |
pcUInt |
unix, baseunix, unixtype |
|
Pointer to cuLong type. |
pculong |
unix, baseunix, unixtype |
|
Alias for cunsigned |
pcunsigned |
unix, baseunix, unixtype |
|
Pointer to cuShort type. |
pcushort |
unix, baseunix, unixtype |
|
Pointer to TDev type. |
pDev |
unix, baseunix, unixtype |
|
PDir |
Pointer to TDir record |
PDir |
baseunix |
pdirent |
Pointer to Dirent record. |
pdirent |
baseunix |
pfdset |
Pointer to FDSet array. |
pfdset |
baseunix |
Pointer to TFilDes type. |
pFilDes |
baseunix |
|
pfpstate |
Pointer to tfpstate record. |
pfpstate |
baseunix |
Pointer to TGid type. |
pGid |
unix, baseunix, unixtype |
|
pglob |
Pointer to TGlob record. |
||
Pointer to TGrpArr array. |
pGrpArr |
baseunix |
|
Process ID type. |
pid_t |
unix, baseunix, unixtype |
|
Pointer to TIno type. |
pIno |
unix, baseunix, unixtype |
|
Pointer to TIno64 type. |
pIno64 |
baseunix |
|
Pointer to TkDev type. |
pkDev |
unixtype |
|
Pointer to TMode type. |
pMode |
unix, baseunix, unixtype |
|
Pointer to TnLink type. |
pnLink |
unix, baseunix, unixtype |
|
Pointer to TOff type. |
pOff |
unix, baseunix, unixtype |
|
Pointer to TOff64 type. |
pOff64 |
baseunix |
|
Pointer to TPid type. |
pPid |
unix, baseunix, unixtype |
|
PSigActionRec |
Pointer to SigActionRec record. |
PSigActionRec |
baseunix |
PSigAltStack |
Pointer to SigAltStack record |
||
Pointer to TSigContext record |
PSigContext |
baseunix |
|
PSigContextRec |
Pointer to SigContextRec record |
||
Pointer to TSigInfo record type. |
psiginfo |
baseunix |
|
PSignalHandler |
Pointer to SignalHandler type. |
PSignalHandler |
baseunix |
PSignalRestorer |
Pointer to SignalRestorer type |
PSignalRestorer |
baseunix |
PSigSet |
Pointer to signal set. |
PSigSet |
baseunix |
Pointer to sigset_t type. |
psigset_t |
baseunix |
|
Pointer to TSize type. |
pSize |
unix, baseunix, unixtype |
|
Pointer to size_t type. |
psize_t |
unixtype |
|
Pointer to TSockLen type. |
pSocklen |
unix, baseunix, unixtype |
|
Pointer to TsSize type |
psSize |
unix, baseunix, unixtype |
|
pstack_t |
Pointer to stack_t record |
||
PStat |
Pointer to Stat record. |
PStat |
baseunix |
PStatFS |
Pointer to StatFS record. |
PStatFS |
unixtype |
PSysCallRegs |
Pointer to SysCallRegs record. |
||
PSysInfo |
Pointer to TSysInfo record. |
PSysInfo |
linux |
Thread attributes record. Opaque. |
pthread_attr_t |
unixtype |
|
Conditional variable attributes type (opaque). |
pthread_condattr_t |
unixtype |
|
Thread conditional variable type. |
pthread_cond_t |
unix, baseunix, unixtype |
|
Thread local storage key (opaque) |
pthread_key_t |
unixtype |
|
Mutex attributes type (opaque). |
pthread_mutexattr_t |
unixtype |
|
Thread mutex type. |
pthread_mutex_t |
unix, baseunix, unixtype |
|
Thread mutex type (opaque). |
pthread_mutex_t |
unixtype |
|
R/W lock attributes (opaque). |
pthread_rwlockattr_t |
unixtype |
|
Read/Write lock type (opaque) |
pthread_rwlock_t |
unixtype |
|
Posix thread type. |
pthread_t |
unix, baseunix, unixtype |
|
Pointer to TTime type. |
pTime |
unix, baseunix, unixtype |
|
Pointer to timespec type. |
ptimespec |
unix, baseunix, unixtype |
|
ptimeval |
Pointer to TTimeVal record |
ptimeval |
unix, baseunix, unixtype |
ptimezone |
Pointer to TimeZone record. |
ptimezone |
baseunix |
Pointer to time_t type. |
ptime_t |
unix, baseunix, unixtype |
|
Pointer to TTms type. |
PTms |
baseunix |
|
Pointer to TUid type. |
pUid |
unix, baseunix, unixtype |
|
PUTimeBuf |
Pointer to TUTimeBuf record |
PUTimeBuf |
baseunix |
PUTSName |
Pointer to TUTSName record. |
PUTSName |
baseunix |
Pointer to wchar_t type. |
pwchar_t |
unixtype |
|
Scheduling parameter description record. |
sched_param |
unixtype |
|
Semaphore type. (opaque) |
sem_t |
unixtype |
|
Callback prototype for a SigActionRec record. |
SigActionHandler |
baseunix |
|
SigActionRec |
Record used in fpSigAction call. |
SigActionRec |
baseunix |
SigAltStack |
Alternate stack registers record |
||
SigContextRec |
Record describing the context of the program when it receives a signal |
||
SignalHandler |
Function prototype for the Signal call. |
SignalHandler |
baseunix |
SignalRestorer |
Signal restorer function prototype |
SignalRestorer |
baseunix |
SigSet |
Signal set type |
SigSet |
baseunix |
Signal set type |
sigset_t |
baseunix |
|
Size_T |
Size type |
Size_T |
unix, baseunix, unixtype |
Socket address length type. |
socklen_t |
unix, baseunix, unixtype |
|
Small size type. |
ssize_t |
unix, baseunix, unixtype |
|
stack_t |
Alias for SigAltStack type |
||
Stat |
Record describing an inode (file) in the pffstat call. |
Stat |
baseunix |
Statfs |
Record describing a file system in the fsstat call. |
||
SysCallRegs |
Register describing system calls. |
||
Alias for Blkcnt_t type. |
TBlkCnt |
baseunix |
|
Alias for blksize_t type. |
TBlkSize |
baseunix |
|
Alias for clock_t type. |
TClock |
unix, baseunix, unixtype |
|
TCloneFunc |
Clone function prototype. |
TCloneFunc |
linux |
Alias for dev_t type. |
TDev |
unix, baseunix, unixtype |
|
TDir |
Record used in OpenDir and ReadDir calls |
TDir |
baseunix |
TDirEnt |
Alias for DirEnt record |
TDirEnt |
baseunix |
Termio |
Terminal I/O description record (small) |
||
Termios |
Terminal I/O description record |
||
TFDSet |
Alias for FDSet type. |
TFDSet |
baseunix |
Array of file descriptors as used in fpPipe call. |
TFilDes |
baseunix |
|
tfpreg |
Record describing floating point register in signal handler. |
tfpreg |
baseunix |
tfpstate |
Record describing floating point unit in signal handler. |
tfpstate |
baseunix |
Describes the search strategy used by FSearch |
TFSearchOption |
unix |
|
Alias for gid_t type. |
TGid |
unix, baseunix, unixtype |
|
Array of gid_t IDs |
TGrpArr |
baseunix |
|
tglob |
Record containing one entry in the result of Glob |
||
timespec |
Time interval for the NanoSleep function. |
timespec |
unix, baseunix, unixtype |
timeval |
Record specifying a time inteval. |
timeval |
unix, baseunix, unixtype |
timezone |
Record describing a timezone |
timezone |
baseunix |
Time span type |
time_t |
unix, baseunix, unixtype |
|
tmmapargs |
Record containing mmap args. |
||
Alias for ino_t type. |
TIno |
unix, baseunix, unixtype |
|
Alias for ino64_t type. |
TIno64 |
baseunix |
|
Alias for kDev_t type. |
TkDev |
unixtype |
|
Alias for mode_t type. |
TMode |
unix, baseunix, unixtype |
|
Record containing timings for fpTimes call. |
tms |
baseunix |
|
Alias for nlink_t type. |
TnLink |
unix, baseunix, unixtype |
|
Alias for off_t type. |
TOff |
unix, baseunix, unixtype |
|
Alias for off64_t type. |
TOff64 |
baseunix |
|
Alias for pid_t type. |
TPid |
unix, baseunix, unixtype |
|
Tpipe |
Array describing a pipe pair of filedescriptors. |
Tpipe |
unix |
TSigAction |
Function prototype for SigAction call. |
||
Alias for SigActionRec record type. |
TSigActionRec |
baseunix |
|
Record describing the CPU context when a signal occurs. |
TSigContext |
baseunix |
|
Record describing the signal when a signal occurs. |
tsiginfo |
baseunix |
|
Alias for SigSet type. |
TSigSet |
baseunix |
|
Alias for size_t type |
TSize |
unix, baseunix, unixtype |
|
Alias for socklen_t type. |
TSocklen |
unix, baseunix, unixtype |
|
Alias for ssize_t type |
TsSize |
unix, baseunix, unixtype |
|
TStat |
Alias for Stat record. |
TStat |
baseunix |
TStatFS |
Alias for StatFS type. |
TStatFS |
unix, baseunix, unixtype |
TSysCallRegs |
Alias for SysCallRegs record |
||
TSysinfo |
Record with system information, used by the SysInfo call. |
TSysinfo |
linux |
TTermio |
Alias for TermIO record |
||
TTermios |
Alias for Termios record. |
||
Alias for TTime type. |
TTime |
unix, baseunix, unixtype |
|
Alias for TimeSpec type. |
Ttimespec |
unix, baseunix, unixtype |
|
TTimeVal |
Alias for TimeVal record. |
TTimeVal |
unix, baseunix, unixtype |
TTimeZone |
Alias for TimeZone record. |
TTimeZone |
baseunix |
Alias for Tms record type. |
TTms |
baseunix |
|
Alias for uid_t type. |
TUid |
unix, baseunix, unixtype |
|
TUTimeBuf |
Alias for UTimBuf record. |
TUTimeBuf |
baseunix |
TUTSName |
Alias for UTSName record. |
TUTSName |
baseunix |
TWinSize |
Alias for WinSize record. |
||
User ID type |
uid_t |
unix, baseunix, unixtype |
|
UTimBuf |
Record used in Utime to set file access and modificaton times. |
UTimBuf |
baseunix |
UTimeBuf |
Alias for UTimBuf record. |
||
utsname |
Record used to return kernel information in UName function. |
utsname |
baseunix |
Wide character type. |
wchar_t |
unixtype |
|
Wide character size type. |
wint_t |
unixtype |
|
winsize |
Record describing terminal window size. |
||
Fast lock (mutex) type (opaque). |
_pthread_fastlock |
unixtype |
в) процедуры и функции:
Название (1.x) |
Описание |
Название (2.x) |
Модуль |
Access |
Check file access |
fpAccess |
baseunix |
Alarm |
Schedule an alarm signal to be delivered |
fpAlarm |
baseunix |
Concert an array of string to an array of null-terminated strings |
ArrayStringToPPchar |
unixutil |
|
AssignPipe |
Create a set of pipe file handlers |
AssignPipe |
unix |
AssignStream |
Assign stream for in and output to a program |
AssignStream |
unix |
Basename |
Return basename of a file |
Basename |
unixutil |
CFMakeRaw |
Sets flags in Termios record. |
||
CFSetISpeed |
Set input baud rate in Termios record |
||
CFSetOSpeed |
Set output baud rate in Termios record |
||
Chmod |
Change file permission bits |
fpChmod |
baseunix |
Chown |
Change owner of file |
fpChown |
baseunix |
Clone |
Clone current process (create new thread) |
Clone |
linux |
CloseDir |
Close directory file descriptor |
fpCloseDir |
baseunix |
CreateShellArgV |
Create an array of null-terminated strings |
||
Dirname |
Extract directory part from filename |
Dirname |
unixutil |
Dup |
Duplicate a file handle |
fpDup |
baseunix |
Dup2 |
Duplicate one filehandle to another |
fpDup2 |
baseunix |
EpochToLocal |
Convert epoch time to local time |
EpochToLocal |
unixutil |
Execl |
Execute process (using argument list) |
FpExecL |
unix |
Execle |
Execute process (using argument list, environment) |
FpExecLE |
unix |
Execlp |
Execute process (using argument list, environment; search path) |
FpExecLP |
unix |
Execv |
Execute process |
FpExecV |
unix, baseunix |
Execve |
Execute process using environment |
fpExecve |
baseunix |
Execvp |
Execute process, search path |
FpExecVP |
unix |
Execute process, search path using environment |
FpExecVPE |
unix |
|
ExitProcess |
Exit the current process |
fpExit |
baseunix |
Fcntl |
File control operations. |
fpFcntl |
baseunix |
fdClose |
Close file descriptor |
fpClose |
baseunix |
fdFlush |
Flush kernel file buffer |
||
fdOpen |
Open file and return file descriptor |
fpOpen |
baseunix |
fdRead |
Read data from file descriptor |
fpRead |
baseunix |
fdSeek |
Set file pointer position. |
FpLseek |
baseunix |
fdTruncate |
Truncate file on certain size. |
FpFtruncate |
baseunix |
fdWrite |
Write data to file descriptor |
fpWrite |
baseunix |
FD_Clr |
Clears a filedescriptor in a set |
fpFD_Clr |
baseunix |
FD_IsSet |
Check whether a filedescriptor is set |
fpFD_IsSet |
baseunix |
FD_Set |
Set a filedescriptor in a set |
fpFD_Set |
baseunix |
FD_Zero |
Clear all file descriptors in set |
fpFD_Zero |
baseunix |
FExpand |
Expand filename to fully qualified path |
||
Flock |
Lock a file (advisory lock) |
fpFlock |
unix |
FNMatch |
Check whether filename matches wildcard specification |
FNMatch |
unixutil |
Fork |
Create child process |
fpFork |
baseunix |
Change current working directory. |
FpChdir |
baseunix |
|
Set all filedescriptors in the set. |
fpfdfillset |
baseunix |
|
Retrieve the current working directory. |
FpGetcwd |
baseunix |
|
Retrieve extended error information. |
fpgeterrno |
baseunix |
|
Get the list of supplementary groups. |
FpGetgroups |
baseunix |
|
Get process group ID |
FpGetpgrp |
baseunix |
|
Create a new directory |
FpMkdir |
baseunix |
|
Create a set of pipe file handlers |
FpPipe |
baseunix |
|
Rename file |
FpRename |
baseunix |
|
Remove a directory. |
FpRmdir |
baseunix |
|
Set extended error information. |
fpseterrno |
baseunix |
|
Set the current group ID |
FpSetgid |
baseunix |
|
Create a new session |
FpSetsid |
baseunix |
|
Set kernel time |
fpsettimeofday |
baseunix |
|
Set the current user ID |
FpSetuid |
baseunix |
|
Set a signal in a signal set. |
FpSigAddSet |
baseunix |
|
Remove a signal from a signal set. |
FpSigDelSet |
baseunix |
|
Clear all signals from signal set. |
FpsigEmptySet |
baseunix |
|
Set all signals in signal set. |
FpSigFillSet |
baseunix |
|
Check whether a signal appears in a signal set. |
FpSigIsMember |
baseunix |
|
Suspend process for several seconds |
FpSleep |
baseunix |
|
Retrieve file information about a file descriptor. |
FpStat |
baseunix |
|
Return execution times for the current process |
FpTimes |
baseunix |
|
Wait for a child to exit. |
FpWait |
baseunix |
|
FReName |
Rename file |
||
FSearch |
Search for file in search path. |
FSearch |
unix |
FSplit |
Split filename into path, name and extension |
FSplit |
unixutil |
FSStat |
Retrieve filesystem information. |
||
FStat |
Retrieve information about a file |
fpFStat |
baseunix |
Retrieve filesystem information from a file descriptor. |
fStatFS |
unix |
|
Synchronize file's kernel data with disk. |
fsync |
unix |
|
GetDate |
Return the system date |
||
GetDateTime |
Return system date and time |
||
GetDomainName |
Return current domain name |
GetDomainName |
unix |
GetEGid |
Return effective group ID |
fpGetEGid |
baseunix |
GetEnv |
Return value of environment variable. |
fpGetEnv |
baseunix |
GetEpochTime |
Return the current unix time |
fptime |
baseunix |
GetEUid |
Return effective user ID |
fpGetEUid |
baseunix |
GetFS |
Return file selector |
GetFS |
unixutil |
GetGid |
Return real group ID |
fpGetGid |
baseunix |
GetHostName |
Return host name |
GetHostName |
unix |
GetLocalTimezone |
Return local timzeone information |
GetLocalTimezone |
unix |
GetPid |
Return current process ID |
fpGetPid |
baseunix |
GetPPid |
Return parent process ID |
fpGetPPid |
baseunix |
GetPriority |
Return process priority |
fpGetPriority |
baseunix |
GetTime |
Return current system time |
||
GetTimeOfDay |
Return kernel time of day in GMT |
fpGetTimeOfDay |
unix |
GetTimezoneFile |
Return name of timezone information file |
GetTimezoneFile |
unix |
GetUid |
Return current user ID |
fpGetUid |
baseunix |
Glob |
Find filenames matching a wildcard pattern |
||
Globfree |
Free result of Glob call |
||
Converts a gregorian date to a julian date |
GregorianToJulian |
unixutil |
|
Converts a julian date to a gregorian date |
JulianToGregorian |
unixutil |
|
IOCtl |
General kernel IOCTL call. |
fpIOCtl |
baseunix |
IOperm |
Set permission on IO ports |
fpIOperm |
x86 |
IoPL |
Set I/O privilege level |
fpIoPL |
x86 |
IsATTY |
Check if filehandle is a TTY (terminal) |
||
Kill |
Send a signal to a process |
fpKill |
baseunix |
Link |
Create a hard link to a file |
fpLink |
baseunix |
LocalToEpoch |
Convert local time to epoch (unix) time |
LocalToEpoch |
unixutil |
Lstat |
Return information about symbolic link. Do not follow the link |
fpLstat |
baseunix |
mkFifo |
Create FIFO (named pipe) in file system |
fpmkFifo |
baseunix |
MMap |
Create memory map of a file |
fpMMap |
baseunix |
MUnMap |
Unmap previously mapped memory block |
fpMUnMap |
baseunix |
NanoSleep |
Suspend process for a short time |
fpNanoSleep |
baseunix |
Nice |
Set process priority |
fpNice |
baseunix |
Octal |
Convert octal to decimal value |
||
OpenDir |
Open directory for reading |
fpOpenDir |
baseunix |
Pause |
Wait for a signal |
fpPause |
baseunix |
PClose |
Close file opened with POpen |
PClose |
unix |
POpen |
Pipe file to standard input/output of program |
POpen |
unix |
ReadDir |
Read entry from directory |
fpReadDir |
baseunix |
ReadLink |
Read destination of symbolic link |
ReadLink |
baseunix |
Read data from a PC port |
ReadPort |
x86 |
|
Read bytes from a PC port |
ReadPortB |
x86 |
|
Read longints from a PC port |
ReadPortL |
x86 |
|
Read Words from a PC port |
ReadPortW |
x86 |
|
ReadTimezoneFile |
Read the timezone file and initialize time routines |
ReadTimezoneFile |
unix |
SeekDir |
Seek to position in directory |
SeekDir |
unix |
Select |
Wait for events on file descriptors |
fpSelect |
baseunix |
SelectText |
Wait for event on typed ontyped file. |
SelectText |
unix |
SetDate |
Set the current system date. |
||
SetDateTime |
Set the current system date and time |
||
SetPriority |
Set process priority |
fpSetPriority |
baseunix |
SetTime |
Set the current system time. |
||
Shell |
Execute and feed command to system shell |
Shell |
unix |
SigAction |
Install signal handler |
fpSigAction |
baseunix |
Signal |
Install signal handler (deprecated) |
fpSignal |
baseunix |
SigPending |
Return set of currently pending signals |
fpSigPending |
baseunix |
SigProcMask |
Set list of blocked signals |
fpSigProcMask |
baseunix |
SigRaise |
Raise a signal (send to current process) |
SigRaise |
unix |
SigSuspend |
Set signal mask and suspend process till signal is received |
fpSigSuspend |
baseunix |
Retrieve filesystem information from a path. |
StatFS |
unix |
|
StringToPPChar |
Split string in list of null-terminated strings |
StringToPPChar |
unixutil |
SymLink |
Create a symbolic link |
fpSymLink |
baseunix |
SysCall |
Execute system call. |
||
Sysinfo |
Return kernel system information |
Sysinfo |
linux |
Execute and feed command to system shell |
fpSystem |
unix |
|
S_ISBLK |
Is file a block device |
fpS_ISBLK |
baseunix |
S_ISCHR |
Is file a character device |
fpS_ISCHR |
baseunix |
S_ISDIR |
Is file a directory |
fpS_ISDIR |
baseunix |
S_ISFIFO |
Is file a FIFO |
fpS_ISFIFO |
baseunix |
S_ISLNK |
Is file a symbolic link |
fpS_ISLNK |
baseunix |
S_ISREG |
Is file a regular file |
fpS_ISREG |
baseunix |
S_ISSOCK |
Is file a unix socket |
fpS_ISSOCK |
baseunix |
TCDrain |
Terminal control: Wait till all data was transmitted |
||
TCFlow |
Terminal control: Suspend transmission of data |
||
TCFlush |
Terminal control: Discard data buffer |
||
TCGetAttr |
Terminal Control: Get terminal attributes |
||
TCGetPGrp |
Terminal control: Get process group |
||
TCSendBreak |
Terminal control: Send break |
||
TCSetAttr |
Terminal control: Set attributes |
||
TCSetPGrp |
Terminal control: Set process group |
||
TellDir |
Return current location in a directory |
TellDir |
unix |
TTYname |
Terminal control: Get terminal name |
||
Umask |
Set file creation mask. |
fpUmask |
baseunix |
Uname |
Return system name. |
fpUname |
baseunix |
UnLink |
Unlink (i.e. remove) a file. |
fpUnLink |
baseunix |
Utime |
Set access and modification times of a file (touch). |
Utime |
baseunix |
WaitPid |
Wait for a process to terminate |
fpWaitPid |
baseunix |
WaitProcess |
Wait for process to terminate. |
WaitProcess |
unix |
WEXITSTATUS |
Extract the exit status from the WaitPID result. |
WEXITSTATUS |
baseunix |
WIFEXITED |
Check whether the process exited normally |
WIFEXITED |
baseunix |
WIFSIGNALED |
Check whether the process was exited by a signal. |
WIFSIGNALED |
baseunix |
WIFSTOPPED |
Check whether the process is currently stopped. |
WIFSTOPPED |
unix |
Write data to PC port |
WritePort |
x86 |
|
Write byte to PC port |
WritePortB |
x86 |
|
Write longint to PC port. |
WritePortl |
x86 |
|
Write Word to PC port |
WritePortW |
x86 |
|
WSTOPSIG |
Return the exit code from the process. |
WSTOPSIG |
baseunix |
WTERMSIG |
Return the signal that caused a process to exit. |
WTERMSIG |
baseunix |
W_EXITCODE |
Construct an exit status based on an return code and signal. |
W_EXITCODE |
unix |
W_STOPCODE |
Construct an exit status based on a signal. |
W_STOPCODE |
unix |
г) переменные:
Название (1.x) |
Описание |
Название (2.x) |
Модуль |
ErrNo |
Error number of last operation. |
||
LinuxError |
Last operating system error |
||
tzdaylight |
Indicates whether daylight savings time is active. |
tzdaylight |
unix |
tzname |
Timezone name. |
tzname |
unix |
tzseconds |
Seconds west of GMT |
tzseconds |
unixutil, unix |
Пример аккуратный выход
Предположим, что программа использует временный рабочий файл. Следующая простая процедура удаляет файл:
(* Аккуратный выход из программы *)
uses linux;
procedure g_exit(s:integer);cdecl;
begin
unlink ('tempfile');
writeln (stderr, 'Прерывание - выход из программы');
halt(1);
end;
Можно связать эту процедуру с определенным сигналом:
var
act:sigactionrec;
.
.
act.handler.sh := @g_exit;
sigaction (SIGINT, @act, nil);
Если после этого вызова пользователь нажмет клавишу прерывания, то управление будет автоматически передано процедуре g_exit. Можно дополнить процедуру g_exit другими необходимыми для завершения операциями.
Пример copyfile
Теперь можем закрепить материал на практике. Задача состоит в написании функции copyfile, которая будет копировать содержимое одного файла в другой. Возвращаемое значение должно быть равно нулю в случае успеха или отрицательному числу – в случае ошибки.
Основная логика действий понятна: открыть первый файл, затем создать второй и выполнять чтение из первого файла и запись во второй до тех пор, пока не будет достигнут конец первого файла. И, наконец, закрыть оба файла.
Окончательное решение может выглядеть таким образом:
(* Программа copyfile: скопировать файл name1 в файл name2 *)
uses linux;
const
BUFSIZE=512; (* Размер считываемого блока *)
PERM=0644; (* Права доступа для нового файла в форме,
похожей на восьмеричную *)
(* Скопировать файл name1 в файл name2 *)
function copyfile(name1, name2: string):integer;
var
infile, outfile: integer; (*дескрипторы файлов*)
nread: longint;
buffer: array [0..BUFSIZE-1] of byte; (*буфер для чтения/записи*)
begin
infile := fdopen (name1, Open_RDONLY);
if infile=-1 then
begin
copyfile:=-1; (*ошибка открытия первого файла*)
exit;
end;
outfile := fdopen (name2, Open_WRONLY or Open_CREAT or Open_TRUNC, octal(PERM));
if outfile=-1 then
begin
fdclose(infile);
copyfile:=-2; (*ошибка открытия второго файла*)
exit;
end;
(* Чтение из файла name1 по BUFSIZE символов *)
nread := fdread (infile, buffer, BUFSIZE);
while nread > 0 do
begin
(* Записать buffer в выходной файл. *)
if fdwrite (outfile, buffer, nread) < nread then
begin
fdclose (infile);
fdclose (outfile);
copyfile:=-3; (* ошибка записи *)
exit;
end;
nread := fdread (infile, buffer, BUFSIZE);
end;
(*закрываем прочитанные файлы*)
fdclose (infile);
fdclose (outfile);
if (nread = -1) then
copyfile := -4 (* ошибка при последнем чтении *)
else
copyfile := 0; (* все порядке *)
end;
(* Программа для тестирования функции copyfile *)
var
retcode:integer;
begin
if paramcount<2 then
begin
writeln('Используйте: ',paramstr(0),' файл-источник файл-приемник');
exit;
end;
retcode := copyfile(paramstr(1), paramstr(2));
case retcode of
0: writeln('Файл ',paramstr(1),' успешно скопирован в файл ',paramstr(2));
-1: writeln('Ошибка открытия файла ',paramstr(1),' для чтения');
-2: writeln('Ошибка открытия файла ',paramstr(2),' для записи');
-3: writeln('Ошибка записи в файл ',paramstr(2));
-4: writeln('Ошибка чтения из файла ',paramstr(1));
end;
end.
Теперь функцию copyfile можно вызывать так:
retcode := copyfile('squarepeg', 'roundhole');
Упражнение 2.6. Измените функцию copyfile так, чтобы в качестве ее параметров могли выступать дескрипторы, а не имена файлов. Проверьте работу новой версии программы.
Упражнение 2.7. Если вы умеете работать с аргументами командной строки, используйте одну из процедур copyfile для создания программы mycp, копирующей первый заданный в командной строке файл во второй.
Пример docommand
Модуль stdio предоставляет библиотечную процедуру runshell, которая позволяет выполнить в программе команду оболочки. Для примера создадим упрощенную версию этой процедуры docommand, используя вызовы fork и ехес. В качестве посредника вызовем стандартную оболочку (заданную именем /bin/sh), а не будем пытаться выполнять программу напрямую. Это позволит программе docommand воспользоваться преимуществами, предоставляемыми оболочкой, например, раскрытием шаблонов имен файлов. Задание параметра -с
вызова оболочки определяет, что команды передаются не со стандартного ввода, а берутся из следующего строчного аргумента.
(* Программа docommand -- запуск команды оболочки, первая версия *)
uses linux,stdio;
function docommand(command:pchar):integer;
var
pid:longint;
begin
pid := fork;
if pid < 0 then
begin
docommand:=-1;
exit;
end;
if pid = 0 then (* дочерний процесс *)
begin
linuxexecl('/bin/sh', 'sh', ['-c', command, nil]);
perror ('execl');
halt(1);
end;
(* Код родительского процесса *)
(* Ожидание возврата из дочернего процесса *)
wait(nil);
docommand:=0;
end;
begin
docommand('ls -l | wc -l');
end.
Следует сказать, что это только первое приближение к настоящей библиотечной процедуре runshell. Например, если конечный пользователь программы нажмет клавишу прерывания во время выполнения команды оболочки, то и вызывающая программа, и команда остановятся. Существуют способы обойти это ограничение, которые будут рассмотрены в следующей главе.
Пример: гостиница
В качестве несколько надуманного, но возможно наглядного примера, предположим, что имеется файл residents, в котором записаны фамилии постояльцев гостиницы. Первая строка содержит фамилию жильца комнаты 1, вторая – жильца комнаты 2 и т.д. (очевидно, это гостиница с прекрасно организованной системой нумерации комнат). Длина каждой строки составляет ровно 41 символ, в первые 40 из которых записана фамилия жильца, а 41-й символ является символом перевода строки для того, чтобы файл можно было вывести на дисплей при помощи команды UNIX cat.
Следующая функция getoccupier вычисляет по заданному целому номеру комнаты положение первого байта фамилии жильца, затем перемещается в эту позицию и считывает данные. Она возвращает либо указатель на строку с фамилией жильца, либо нулевой указатель в случае ошибки (мы будем использовать для этого значение nil). Обратите внимание, что мы присвоили переменной дескриптора файла infile исходное значение –1. Благодаря этому мы можем гарантировать, что файл будет открыт всего один раз.
(* Функция getoccupier - получить фамилию из файла residents *)
uses linux;
const
NAMELENGTH=41;
var
namebuf:array [0..NAMELENGTH-1] of char; (* Буфер для фамилии *)
const
infile:integer=-1; (* Для хранения дескриптора файла *)
function getoccupier(roomno:integer):pchar;
var
offset, nread:longint;
begin
(* Убедиться, что файл открывается впервые *)
if infile = -1 then
begin
infile := fdopen ('residents', Open_RDWR);
if infile = -1 then
begin
getoccupier := nil; (* Невозможно открыть файл *)
exit;
end;
end;
offset := (roomno - 1) * NAMELENGTH;
(* Найти поле комнаты и считать фамилию жильца *)
if fdseek (infile, offset, SEEK_SET) = -1 then
begin
getoccupier := nil;
exit;
end;
nread := fdread (infile, namebuf, NAMELENGTH);
if nread <= 0 then
begin
getoccupier := nil;
exit;
end;
(* Создать строку, заменив символ перевода строки на '\0' *)
namebuf[nread - 1] := #0;
getoccupier := namebuf;
end;
Если предположить, что в гостинице 10 комнат, то следующая программа будет последовательно вызывать функцию getoccupier для просмотра файла и выводить каждую найденную фамилию при помощи процедуры writeln из стандартного модуля system:
(* Программа listoc выводит все фамилии жильцов *)
const
NROOMS=10;
var
j:integer;
p:pchar;
begin
for j := 1 to NROOMS do
begin
p := getoccupier (j);
if p<>nil then
writeln('Комната ', j:2, ', ', p)
else
writeln('Ошибка для комнаты ', j);
end;
end.
Упражнение 2.9. Придумайте алгоритм для определения пустых комнат. Измените функцию getoccupier и файл данных, если это необходимо, так, чтобы он отражал эти изменения. Затем напишите процедуру с названием findfree для поиска свободной комнаты с наименьшим номером.
Упражнение 2.10. Напишите процедуру freeroom для удаления записи о жильце. Затем напишите процедуру addguest для внесения новой записи о жильце, с предварительной проверкой того, что выделяемая комната свободна.
Упражнение 2.11. Объедините процедуры getoccupier, freeroom, addguest и findfree в простой программе с названием frontdesk, которая управляет файлом данных. Используйте аргументы командной строки или напишите интерактивную программу, которая вызывает функции writeln и readln. В обоих случаях для вычисления номера комнаты вам потребуется преобразовывать строки в целые числа. Вы можете использовать для этого библиотечную процедуру StrToInt:
i := StrToInt(str);
где string – указатель на строку символов, а i
– целое число.
Упражнение 2.12. В качестве обобщенного примера напишите программу на основе системного вызова fdseek, которая копирует в обратном порядке байты из одного файла в другой. Насколько эффективным получилось ваше решение?
Упражнение 2.13. Используя вызов fdseek, напишите процедуры для копирования последних 10 символов, последних 10 слов и последних 10 строк из одного файла в другой.
Пример игнорирование сигнала SIGINT
Для того чтобы процесс игнорировал сигнал прерывания SIGINT, все, что нужно для этого сделать – это заменить следующую строку в программе:
act.handler.sh := @catchint;
на
act.handler.sh := SIG_IGN;
После выполнения этого оператора нажатие клавиши прерывания будет безрезультатным. Снова разрешить прерывание можно так:
act.handler.sh := SIG_DFL;
sigaction (SIGINT, @act, nil);
Можно игнорировать сразу несколько сигналов, например:
act.handler.sh := SIG_IGN;
sigaction(SIGINT, @act, nil);
При этом игнорируются оба сигнала SIGINT и SIGQUIT. Это может быть полезно в программах, которые не должны прерываться с клавиатуры.
Некоторые командные интерпретаторы используют этот подход, чтобы гарантировать, что фоновые процессы не останавливаются при нажатии пользователем клавиши прерывания. Это возможно вследствие того, что игнорируемые процессом сигналы будут игнорироваться и после вызова ехес. Поэтому командный интерпретатор может вызвать sigaction для игнорирования сигналов SIGQUIT и SIGINT, а затем запустить новую программу при помощи вызова ехес.
Пример использования функции malloc: связные списки
В информатике существует множество типов динамических структур данных. Одним из классических примеров таких структур является связный список, в котором группа одинаковых объектов связывается в единый логический объект. В этом разделе составляется простой пример, использующий односвязный список для демонстрации применения функций семейства malloc.
(* list.inc - заголовочный файл для примера. *)
uses strings,stdio;
(* Определение основной структуры *)
type
pMEMBER=^MEMBER;
MEMBER=record
m_data:pchar;
m_next:pMEMBER;
end;
ppMEMBER=^pMEMBER;
(* Определение функций *)
function new_member(data:pchar):pMEMBER;forward;
procedure add_member(head:ppMEMBER; newmem:pMEMBER);forward;
procedure free_list (head:ppMEMBER);forward;
procedure printlist (listhead:pMEMBER);forward;
Оператор type вводит тип MEMBER, имеющий два поля. Первое поле, m_data, в экземпляре типа MEMBER будет указывать на произвольную строку. Второе поле, m_next, указывает на другой объект типа MEMBER.
Каждый элемент в связном списке структур типа MEMBER будет указывать на следующий в списке объект MEMBER, то есть если известен один элемент списка, то следующий можно найти при помощи указателя m_next. Поскольку на каждый объект MEMBER в списке ссылается только один указатель, список можно обходить только в одном направлении. Такие списки называются односвязными (singly linked). Если бы был определен еще один указатель m_prev, то список можно было бы обходить и в обратном направлении, и в этом случае он был бы двусвязным (doubly linked).
Адрес начала, или головы, списка обычно записывается в отдельном указателе, определенным следующим образом:
const
head:pmember = nil;
Конец списка обозначается нулевым значением поля
m_next последнего элемента списка.
На рис. 12.1 показан простой список из трех элементов. Его начало обозначено указателем head.
Теперь представим небольшой набор процедур для работы с этими структурами. Первая функция называется new_member. Она отводит память под структуру MEMBER с помощью вызова malloc. Обратите внимание, что указателю m_next присвоено нулевое значение, в данном случае обозначенное как nil. Это связано с тем, что функция malloc не обнуляет выделяемую память. Поэтому при создании структуры
MEMBER поле m_text может содержать ложный, но правдоподобный адрес.
![](image/index-image030.gif)
Рис. 12.1. Связный список объектов MEMBER
{$i list.inc}
(* Функция new_member - выделить память для нового элемента *)
function new_member (data:pchar):pMEMBER;
var
newmem:pMEMBER;
begin
newmem := malloc (sizeof (MEMBER));
if newmem = nil then
writeln (stderr, 'new_member: недостаточно памяти')
else
begin
(* Выделить память для копирования данных *)
newmem^.m_data := malloc (strlen (data) + 1);
(* Скопировать данные в структуру *)
strcopy (newmem^.m_data, data);
(* Обнулить указатель в структуре *)
newmem^.m_next := nil;
end;
new_member:=newmem;
end;
Следующая процедура add_member добавляет в список, на который указывает head, новый элемент
MEMBER. Как видно из текста процедуры, элемент MEMBER добавляется всегда в начало списка.
{$i list.inc}
(* Процедура add_member - добавить новый элемент MEMBER *)
procedure add_member (head:ppMEMBER; newmem:pMEMBER);
begin
(* Эта простая процедура вставляет новый
* элемент в начало списка
*)
newmem^.m_next := head^;
head^ := newmem;
end;
Последняя процедура – free_list. Она принимает указатель на начало списка head^ и освобождает память, занятую всеми структурами MEMBER, образующими список. Она также обнуляет указатель head^, гарантируя, что в указателе head^ не содержится прежнее значение (иначе при случайном использовании head^ могла бы возникать трудноуловимая ошибка).
{$i list.inc}
(* Процедура free_list - освободить занятую списком память *)
procedure free_list (head:ppMEMBER);
var
curr, next:pMEMBER;
begin
curr := head^;
while curr <> nil do
begin
next := curr^.m_next;
(* Освободить память, занятую данными *)
free (curr^.m_data);
(* Освободить память, отведенную под структуру списка *)
free (curr);
curr := next;
end;
(* Обнулить указатель на начало списка *)
head^ := nil;
end;
Следующая простая программа использует описанные процедуры. Она создает односвязный список, изображенный на рис. 12.1, а затем удаляет его. Обратите внимание на способ обхода списка процедурой
printlist. Используемый в ней цикл while типичен для программ, в которых применяются связные списки.
{$i list.inc}
(* Обход и вывод списка *)
procedure printlist (listhead:pMEMBER);
var
m:pMEMBER;
begin
writeln (#$a'Содержимое списка:');
if listhead = nil then
writeln (#9'(пусто)')
else
begin
m := listhead;
while m <> nil do
begin
writeln (#9, m^.m_data);
m := m^.m_next;
end;
end;
end;
const
strs:array [0..2] of pchar=('again', 'world', 'Hello');
(* Программа для проверки процедур работы со списком *)
var
head, newm:pMEMBER;
j:integer;
begin
(* Инициализация списка *)
head := nil;
(* Добавление элементов к списку *)
for j:=0 to 2 do
begin
newm := new_member (strs[j]);
add_member (@head, newm);
end;
(* Вывести элементы списка *)
printlist (head);
(* Удалить список *)
free_list (@head);
(* Вывести элементы списка *)
printlist (head);
end.
Следует обратить внимание и на то, как в начале программы был инициализирован список присвоением указателю head значения nil. Это важно, так как иначе список мог оказаться заполненным «мусором», что неизбежно привело бы к ошибочной работе или к аварийному завершению программы.
Рассматриваемая программа должна выдать такой результат:
Содержимое списка:
Hello world again
Содержимое списка:
(пусто)
Пример передачи сообщений: очередь с приоритетами
В этом разделе разработаем простое приложение для передачи сообщений. Его целью является реализация очереди, в которой для каждого элемента может быть задан приоритет. Серверный процесс будет выбирать элементы из очереди и обрабатывать их каким-либо образом. Например, элементы очереди могут быть именами файлов, а серверный процесс может копировать их на принтер. Этот пример аналогичен примеру использования FIFO из раздела 7.2.1.
Отправной точкой будет следующий заголовочный файл q.inc:
(* q.h - заголовок для примера очереди сообщений *)
const
QKEY:tkey=(1 shl 6) + 5{0105}; (* ключ очереди *)
QPERM=(6 shl 6) + (6 shl 3){0660}; (* права доступа *)
MAXOBN=50; (* макс. длина имени объекта *)
MAXPRIOR=10; (* максимальный приоритет *)
type
q_entry=record
mtype:longint;
mtext:array [0..MAXOBN] of char;
end;
pq_entry=^q_entry;
Определение QKEY задает значение ключа, которое будет обозначать очередь сообщений в системе. Определение QPERM устанавливает связанные с очередью права доступа. Так как код доступа равен octal(0660), то владелец очереди и члены его группы смогут выполнять чтение и запись. Как увидим позже, определения MAXOBN и MAXPRIOR будут налагать ограничения на сообщения, помещаемые в очередь. Последняя часть этого включаемого файла содержит определение структуры q_entry. Структуры этого типа будут использоваться в качестве сообщений, передаваемых и принимаемых следующими процедурами.
Первая рассматриваемая процедура называется enter, она помещает в очередь имя объекта, заканчивающееся нулевым символом, и имеет следующую форму:
{$i q.inc}
(* Процедура enter - поместить объект в очередь *)
function enter (objname:string;priority:longint):boolean;
var
len, s_qid:longint;
s_entry:q_entry; (* структура для хранения сообщений *)
begin
(* Проверка длины имени и уровня приоритета *)
len := length (objname);
if len > MAXOBN then
begin
warn ('слишком длинное имя');
enter:=false;
exit;
end;
if (priority > MAXPRIOR) or (priority < 0) then
begin
warn ('недопустимый уровень приоритета');
enter:=false;
exit;
end;
(* Инициализация очереди сообщений, если это необходимо *)
s_qid := init_queue;
if s_qid = -1 then
begin
enter:=false;
exit;
end;
(* Инициализация структуры переменной s_entry *)
s_entry.mtype := priority;
strlcopy (s_entry.mtext, @objname[1], MAXOBN);
(* Посылаем сообщение, выполнив ожидание, если это необходимо *)
if not msgsnd (s_qid, @s_entry, len, 0) then
begin
perror ('Ошибка вызова msgsnd');
enter:=false;
exit;
end
else
enter:=true;
end;
Первое действие, выполняемое процедурой
enter, заключается в проверке длины имени объекта и уровня приоритета. Обратите внимание на то, что минимальное значение переменной приоритета priority равно 1, так как нулевое значение приведет к неудачному завершению вызова msgsnd. Затем процедура enter «открывает» очередь, вызывая процедуру init_queue, реализацию которой приведем позже.
После завершения этих действий процедура формирует сообщение и пытается послать его при помощи вызова msgsnd. Здесь для хранения сообщения использована структура s_entry типа q_entry, и последний параметр вызова msgsnd равен нулю. Это означает, что система приостановит выполнение текущего процесса, если очередь заполнена (так как не задан флаг IPC_NOWAIT).
Процедура enter сообщает о возникших проблемах при помощи функции warn или библиотечной функции perror. Для простоты функция warn реализована следующим образом:
procedure warn (s:pchar);
begin
writeln(stderr, 'Предупреждение: ', s);
end;
В реальных системах функция warn должна записывать сообщения в специальный файл протокола.
Назначение функции init_queue очевидно. Она инициализирует идентификатор очереди сообщений или возвращает идентификатор очереди сообщений, который с ней уже связан.
{$i q.inc}
(* Инициализация очереди - получить идентификатор очереди *)
function init_queue:longint;
var
queue_id:longint;
begin
(* Попытка создания или открытия очереди сообщений *)
queue_id := msgget (QKEY, IPC_CREAT or QPERM);
if queue_id = -1 then
perror ('Ошибка вызова msgget');
init_queue:=queue_id;
end;
Следующая процедура, serve, используется серверным процессом для получения сообщений из очереди и противоположна процедуре
enter.
{$i q.inc}
(* Процедура serve - принимает и обрабатывает сообщение обслуживает
* объект очереди с наивысшим приоритетом
*)
function serve:integer;
var
r_qid:longint;
r_entry:q_entry;
begin
(* Инициализация очереди сообщений, если это необходимо *)
r_qid := init_queue;
if r_qid = -1 then
begin
serve:=-1;
exit;
end;
(* Получить и обработать следующее сообщение *)
while true do
begin
if not msgrcv(r_qid, @r_entry, MAXOBN, -1*MAXPRIOR, MSG_NOERROR) then
begin
perror ('Ошибка вызова msgrcv');
serve:=-1;
exit;
end
else
begin
(* Обработать имя объекта *)
proc_obj (@r_entry);
end;
end;
end;
Обратите внимание на вызов msgrcv. Так как в качестве параметра типа задано отрицательное значение (-1 * MAXPRIOR), то система вначале проверяет очередь на наличие сообщений со значением
mtype равным 1, затем равным 2 и так далее, до значения MAXPRIOR включительно. Другими словами, сообщения с наименьшим номером будут иметь наивысший приоритет. Процедура proc_obj работает с объектом. Для системы печати она может просто копировать файл на принтер.
Две следующих простых программы демонстрируют взаимодействие этих процедур: программа etest помещает элемент в очередь, а программа stest обрабатывает его (в действительности она всего лишь выводит содержимое и тип сообщения).
Пример перехват сигнала SIGINT
Этот пример демонстрирует, как можно перехватить сигнал, а также проясняет лежащий в его основе механизм сигналов. Программа sigex просто связывает с сигналом SIGINT функцию catchint, а затем выполняет набор операторов sleep и writeln. В данном примере определена структура act типа sigactionrec как глобальная, поэтому при инициализации структуры все поля, и в частности поле sa_flags обнуляются.
(* Программа sigex - демонстрирует работу sigaction *)
uses linux,stdio;
(* Простая функция для обработки сигнала SIGINT *)
procedure catchint (signo:integer);cdecl;
begin
writeln (#$a'сигнал CATCHINT: signo=', signo);
writeln ('сигнал CATCHINT: возврат'#$a);
end;
var
act,oact:sigactionrec;
mask:sigset_t;
begin
(* Определение процедуры обработчика сигнала catchint *)
(* Задание действия при получении сигнала SIGINT *)
act.handler.sh := @catchint;
(* Создать маску, включающую все сигналы *)
sigfillset (@mask);
act.sa_mask:=mask.__val[0];
(* До вызова процедуры sigaction сигнал SIGINT
* приводил к завершению процесса (действие по умолчанию)
*)
sigaction (SIGINT, @act, @oact);
(* При получении сигнала SIGINT управление
* будет передаваться процедуре catchint
*)
writeln ('вызов sleep номер 1');
sleep (1);
writeln ('вызов sleep номер 2');
sleep (1);
writeln ('вызов sleep номер 3');
sleep (1);
writeln ('вызов sleep номер 4');
sleep (1);
writeln ('Выход');
halt(0);
end.
Сеанс обычного запуска sigex будет выглядеть так:
$ sigex
Вызов sleep номер 1
Вызов sleep номер 2
Вызов sleep номер 3
Вызов sleep номер 4
Выход
Пользователь может прервать выполнение программы sigex, нажав клавишу прерывания задания. Если она была нажата до того, как в программе sigex была выполнена процедура sigaction, то процесс просто завершит работу. Если же нажать да клавишу прерывания после вызова sigaction, то управление будет передано функции catchint:
$ sigex
Вызов sleep номер 1
<прерывание> (пользователь нажимает на клавишу прерывания)
Сигнал CATCHINT: signo = 2
Сигнал CATCHINT: возврат
Вызов sleep номер 2
Вызов sleep номер 3
Вызов sleep номер 4
Выход
Обратите внимание на то, как передается управление из тела программы процедуре catchint. После завершения процедуры catchint, управление продолжится с точки, в которой программа была прервана. Можно попробовать прервать программу sigex и в другом месте:
$ sigex
Вызов sleep номер 1
Вызов sleep номер 2
<прерывание> (пользователь нажимает на клавишу прерывания)
Сигнал CATCHINT: signo = 2
Сигнал GATCHINT: возврат
Вызов sleep номер 3
Вызов sleep номер 4
Выход
Пример работы с разделяемой памятью: программа shmcopy
В этом разделе создадим простую программу shmcopy для демонстрации практического использования разделяемой памяти. Программа shmcopy просто копирует данные со своего стандартного ввода на стандартный вывод, но позволяет избежать лишних простоев в вызовах fdread и fdwrite. При запуске программы shmcopy создаются два процесса, один из которых выполняет чтение, а другой – запись, и которые совместно используют два буфера, реализованных в виде сегментов разделяемой памяти. Когда первый процесс считывает данные в первый буфер, второй записывает содержимое второго буфера, и наоборот. Так как чтение и запись выполняются одновременно, пропускная способность возрастает. Этот подход используется, например, в программах, которые выводят информацию на ленточный накопитель.
Для согласования двух процессов (чтобы записывающий процесс не писал в буфер до тех пор, пока считывающий процесс его не заполнит) будем использовать два семафора. Почти во всех программах, использующих разделяемую память, требуется дополнительная синхронизация, так как механизм разделяемой памяти не содержит собственных средств синхронизации.
Программа shmcopy использует следующий заголовочный файл share_ex.inc:
(* Заголовочный файл для примера работы с разделяемой памятью *)
const
SHMKEY1:tkey=$10; (* ключ разделяемой памяти *)
SHMKEY2:tkey=$15; (* ключ разделяемой памяти *)
SEMKEY :tkey=$20; (* ключ семафора *)
(* Размер буфера для чтения и записи *)
BUFSIZ=8192;
SIZ=5*BUFSIZ;
(* В этой структуре будут находиться данные и счетчик чтения *)
type
databuf=record
d_nread:integer;
d_buf:array [0..SIZ-1] of char;
end;
pdatabuf=^databuf;
Напомним, что постоянная BUFSIZ определена в файле stdio и задает оптимальный размер порций данных при работе с файловой системой. Шаблон databuf показывает структуру, которая связывается с каждым сегментом разделяемой памяти. В частности, элемент d_nread позволит процессу, выполняющему чтение, передавать другому, осуществляющему запись, через участок разделяемой памяти число считанных символов.
Следующий файл содержит процедуры для инициализации двух участков разделяемой памяти и набора семафоров. Он также содержит процедуру remobj, которая удаляет различные объекты межпроцессного взаимодействия в конце работы программы. Обратите внимание на способ вызова shmat для подключения участков разделяемой памяти к адресному пространству процесса.
(* Процедуры инициализации *)
{$i share_ex.inc}
const
IFLAGS=IPC_CREAT or IPC_EXCL;
ERR:pdatabuf=pdatabuf(-1);
var
shmid1, shmid2, semid : longint;
procedure getseg (var p1,p2:pdatabuf);
begin
(* Создать участок разделяемой памяти *)
shmid1 := shmget (SHMKEY1, sizeof (databuf), octal(0600) or IFLAGS);
if shmid1 = -1 then
fatal ('shmget');
shmid2 := shmget (SHMKEY2, sizeof (databuf), octal(0600) or IFLAGS);
if shmid2 = -1 then
fatal ('shmget');
(* Подключить участки разделяемой памяти. *)
p1 := pdatabuf( shmat (shmid1, 0, 0));
if p1 = ERR then
fatal ('shmat');
p2 := pdatabuf( shmat (shmid2, 0, 0));
if p2 = ERR then
fatal ('shmat');
end;
function getsem:longint; (* Получить набор семафоров *)
var
x:tsemun;
begin
x.val := 0;
(* Создать два набора семафоров *)
semid := semget (SEMKEY, 2, octal(0600) or IFLAGS);
if semid = -1 then
fatal ('semget');
(* Задать начальные значения *)
if semctl (semid, 0, SETVAL, x) = -1 then
fatal ('semctl');
if semctl (semid, 1, SETVAL, x) = -1 then
fatal ('semctl');
getsem:=semid;
end;
(* Удаляет идентификаторы разделяемой памяти
* и идентификатор набора семафоров
*)
procedure remobj;
var
x:tsemun;
begin
if not shmctl (shmid1, IPC_RMID, nil) then
fatal ('shmctl');
if not shmctl (shmid2, IPC_RMID, nil) then
fatal ('shmctl');
if semctl (semid, 0, IPC_RMID, x) = -1 then
fatal ('semctl');
end;
Ошибки в этих процедурах обрабатываются при помощи процедуры fatal, которая использовалась в предыдущих примерах. Она просто вызывает perror, а затем halt.
Ниже следует главная функция для программы shmcopy. Она вызывает процедуры инициализации, а затем создает процесс для чтения (родительский) и для записи (дочерний). Обратите внимание на то, что именно выполняющий запись процесс вызывает процедуру remobj при завершении программы.
(* Программа shmcopy - главная функция *)
uses ipc,stdio,linux;
{$i share_ex.inc}
var
pid : longint;
buf1, buf2 : pdatabuf;
begin
(* Инициализация набора семафоров. *)
semid := getsem;
(* Создать и подключить участки разделяемой памяти. *)
getseg (buf1, buf2);
pid := fork;
case pid of
-1:
fatal ('fork');
0: (* дочерний процесс *)
begin
writer (semid, buf1, buf2);
remobj;
end;
else (* родительский процесс *)
reader (semid, buf1, buf2);
end;
halt (0);
end.
Программа создает объекты межпроцессного взаимодействия до вызова fork. Обратите внимание на то, что адреса, определяющие сегменты разделяемой памяти (которые находятся в переменных buf1 и buf2), будут заданы в обоих процессах.
Процедура reader принимает данные со стандартного ввода, то есть из дескриптора файла 0, и является первой функцией, представляющей интерес. Ей передается идентификатор набора семафоров в параметре semid и адреса двух участков разделяемой памяти в переменных buf1 и buf2.
{$i share_ex.inc}
(* Определения процедур p() и v() для двух семафоров *)
const
p1:tsembuf=(sem_num:0;sem_op:-1;sem_flg:0);
p2:tsembuf=(sem_num:1;sem_op:-1;sem_flg:0);
v1:tsembuf=(sem_num:0;sem_op:1;sem_flg:0);
v2:tsembuf=(sem_num:1;sem_op:1;sem_flg:0);
(* Процедура reader - выполняет чтение из файла *)
procedure reader(semid:longint;buf1,buf2:pdatabuf);
begin
while true do
begin
(* Считать в буфер buf1 *)
buf1^.d_nread := fdread (0, buf1^.d_buf, SIZ);
(* Точка синхронизации *)
semop (semid, @v1, 1);
semop (semid, @p2, 1);
(* Чтобы процедура writer не была приостановлена. *)
if buf1^.d_nread <= 0 then
exit;
buf2^.d_nread := fdread (0, buf2^.d_buf, SIZ);
semop (semid, @v2, 1);
semop (semid, @p1, 1);
if buf2^.d_nread <= 0 then
exit;
end;
end;
Структуры sembuf просто определяют операции р() и v() для набора из
двух семафоров. Но на этот раз они используются не для блокировки критических участков кода, а для синхронизации процедур, выполняющих чтение и запись. Процедура reader использует операцию v2 для сообщения о том, что она завершила чтение и ожидает, вызвав semop с параметром р1, пока процедура writer сообщит о завершении записи. Это станет более очевидным при описании процедуры writer. Возможны другие подходы, включающие или четыре бинарных семафора, или семафоры, имеющие более двух значений.
Последней процедурой, вызываемой программой
shmcopy, является процедура writer:
{$i share_ex.inc}
(* Процедура writer - выполняет запись *)
procedure writer(semid:longint;buf1,buf2:pdatabuf);
begin
while true do
begin
semop (semid, @p1, 1);
semop (semid, @v2, 1);
if buf1^.d_nread <= 0 then
exit;
fdwrite (1, buf1^.d_buf, buf1^.d_nread);
semop (semid, @p2, 1);
semop (semid, @v1, 1);
if buf2^.d_nread <= 0 then
exit;
fdwrite (1, buf2^.d_buf, buf2^.d_nread);
end;
end;
И снова следует обратить внимание на использование набора семафоров для согласования работы процедур reader и writer. На этот раз процедура writer использует операцию v2
для сигнализации и ждет р1. Важно также отметить, что значения buf1^.d_nread и buf2^.d_nread устанавливаются процессом, выполняющим чтение.
После компиляции можно использовать программу
shmcopy при помощи подобной команды:
$ shmcopy < big > /tmp/big
Упражнение 8.6. Усовершенствуйте обработку ошибок и вывод сообщений в программе shmcopy (в особенности для вызовов fdread и fdwrite). Сделайте так, чтобы программа shmcopy принимала в качестве аргументов имена файлов в форме команды cat. Какие последствия возникнут при прерывании программы shmcopy? Можете ли вы улучшить поведение программы?
Упражнение 8.7. Придумайте систему передачи сообщений, использующую разделяемую память. Измерьте ее производительность и сравните с производительностью стандартных процедур передачи сообщений.
Пример работы с семафорами
Теперь продолжим пример, который начали с процедуры initsem. Он содержит две процедуры р() и v(), реализующие традиционные операции над семафорами. Сначала рассмотрим р():
{$i pv.inc}
(* Процедура p.pas - операция p для семафора *)
function p (semid:longint):longint;
var
p_buf:tsembuf;
begin
p_buf.sem_num := 0;
p_buf.sem_op := -1;
p_buf.sem_flg := SEM_UNDO;
if not semop (semid, @p_buf, 1) then
begin
perror ('ошибка операции p(semid)');
halt (1);
end;
p:=0;
end;
Обратите внимание на то, что здесь использован флаг SEM_UNDO. Теперь рассмотрим текст процедуры v().
{$i pv.inc}
(* Процедура v.pas - операция v для семафора *)
function v (semid:longint):longint;
var
v_buf:tsembuf;
begin
v_buf.sem_num := 0;
v_buf.sem_op := 1;
v_buf.sem_flg := SEM_UNDO;
if not semop (semid, @v_buf, 1) then
begin
perror ('Ошибка операции v(semid)');
halt (1);
end;
v:=0;
end;
Можно продемонстрировать использование этих довольно простых процедур для реализации взаимного исключения. Рассмотрим следующую программу:
(* Программа testsem - проверка процедур работы с семафорами *)
uses ipc,stdio,linux;
{$i pv.inc}
procedure handlesem (skey:tkey);
var
semid, pid:longint;
begin
pid := getpid;
semid := initsem (skey);
if semid < 0 then
halt (1);
writeln (#$a'Процесс ',pid,' перед критическим участком');
p (semid);
writeln ('Процесс ',pid,' выполняет критический участок');
(* В реальной программе здесь выполняется нечто осмысленное *)
sleep (10);
writeln ('Процесс ',pid,' покинул критический участок');
v (semid);
writeln ('Процесс ',pid,' завершает работу');
halt (0);
end;
const
semkey:tkey = $200;
var
i:integer;
begin
for i := 1 to 3 do
if fork = 0 then
handlesem (semkey);
end.
Программа testsem порождает три дочерних процесса, которые используют вызовы р() и v() для того, чтобы в каждый момент времени только один из них выполнял критический участок. Запуск программы testsem может дать следующий результат:
Процесс 799 перед критическим участком
Процесс 799 выполняет критический участок
Процесс 800 перед критическим участком
Процесс 801 перед критическим участком
Процесс 799 покинул критический участок
Процесс 801 выполняет критический участок
Процесс 799 завершает работу
Процесс 801 покинул критический участок
Процесс 801 завершает работу
Процесс 800 выполняет критический участок
Процесс 800 покинул критический участок
Процесс 800 завершает работу
Пример управления терминалом: программа tscript
Программа tscript устроена следующим образом: при старте она выполняет вызовы fork и ехес для запуска пользовательской оболочки. Далее все данные, записываемые на терминал оболочкой, сохраняются в файле, при этом оболочка ничего об этом не знает и продолжает вести себя так, как будто она полностью управляет дисциплиной линии связи и, следовательно, терминалом. Логическая структура программы tscript показана на рис. 9.6.
![](image/index-image029.gif)
Рис. 9.6. Использование псевдотерминала в программе tscript
Основные элементы схемы:
tscript | Первый запускаемый процесс. После инициализации псевдотерминала и дисциплины линии связи этот процесс использует вызовы fork и ехес для создания оболочки shell. Теперь программа tscript играет две роли. Первая состоит в чтении из настоящего терминала и записи всех данных в порт ведущего устройства псевдотерминала. (Все данные, записываемые в ведущее устройство псевдотерминала, непосредственно передаются на ведомое устройство псевдотерминала.) Вторая роль состоит в чтении вывода программы оболочки shell при помощи псевдотерминала и копировании этих данных на настоящий терминал и в выходной файл | ||
shell | Пользовательская оболочка. Перед запуском процесса shell модули дисциплины линии связи STREAM вставляются в ведомое устройство. Стандартный ввод, стандартный вывод и стандартный вывод диагностики оболочки перенаправляются в ведомое устройство псевдотерминала |
Первая задача программы tscript состоит в установке обработчика сигнала SIGCHLD и в открытии псевдотерминала. Затем программа создает процесс shell. И, наконец, вызывается процедура script. Эта процедура отслеживает два потока данных: ввод с клавиатуры (стандартный ввод), который она передает ведущему устройству псевдотерминала, и ввод с ведущего устройства псевдотерминала, передаваемый на стандартный вывод и записываемый в выходной файл.
(* Программа tscript управление терминалом *)
(* Хотя в Linux этот пример и не работает... *)
uses linux,stdio;
var
dattr:termios;
var
act:sigactionrec;
mfd, sfd:longint;
err:integer;
buf:array [0..511] of char;
mask:sigset_t;
begin
(* Сохранить текущие установки терминала *)
tcgetattr (0, dattr);
(* Открыть псевдотерминал *)
err := pttyopen (mfd, sfd);
if err <> 1 then
begin
writeln (stderr, 'pttyopen: ', err);
perror ('Ошибка при открытии псевдотерминала');
halt (1);
end;
(* Установить обработчик сигнала SIGCHLD *)
act.handler.sh := @catch_child;
sigfillset (@mask);
act.sa_mask:=mask.__val[0];
sigaction (SIGCHLD, @act, nil);
(* Создать процесс оболочки *)
case fork of
-1: (* ошибка *)
begin
perror ('Ошибка вызова оболочки');
halt (2);
end;
0: (* дочерний процесс *)
begin
fdclose (mfd);
runshell (sfd);
end;
else (* родительский процесс *)
begin
fdclose (sfd);
script (mfd);
end;
end;
end.
Основная программа использует четыре процедуры. Первая из них называется catch_child. Это обработчик сигнала SIGCHLD. При получении сигнала SIGCHLD процедура catch_child восстанавливает атрибуты терминала и завершает работу.
procedure catch_child (signo:integer);cdecl;
begin
tcsetattr (0, TCSAFLUSH, dattr);
halt (0);
end;
Вторая процедура, pttyopen, открывает псевдотерминал.
function pttyopen (var masterfd, slavefd:longint):integer;
var
slavenm:pchar;
begin
(* Открыть псевдотерминал -
* получить дескриптор файла главного устройства *)
masterfd := fdopen ('/dev/ptmx', Open_RDWR);
if masterfd = -1 then
begin
pttyopen:=-1;
exit;
end;
(* Изменить права доступа для ведомого устройства *)
if grantpt (masterfd) = -1 then
begin
fdclose (masterfd);
pttyopen:=-2;
exit;
end;
(* Разблокировать ведомое устройство, связанное с mfd *)
if unlockpt (masterfd) = -1 then
begin
fdclose (masterfd);
pttyopen:=-3;
exit;
end;
(* Получить имя ведомого устройства и затем открыть его *)
slavenm := ptsname (masterfd);
if slavenm = nil then
begin
fdclose (masterfd);
pttyopen:=-4;
exit;
end;
slavefd := fdopen (slavenm, Open_RDWR);
if slavefd = -1 then
begin
fdclose (masterfd);
pttyopen:=-5;
exit;
end;
(* Создать дисциплину линии связи *)
ioctl (slavefd, I_PUSH, pchar('ptem'));
if linuxerror>0 then
begin
fdclose (masterfd);
fdclose (slavefd);
pttyopen:=-6;
exit;
end;
ioctl (slavefd, I_PUSH, pchar('ldterm'));
if linuxerror>0 then
begin
fdclose (masterfd);
fdclose (slavefd);
pttyopen:=-7;
exit;
end;
pttyopen:=1;
end;
Третья процедура – процедура runshell. Она выполняет следующие задачи:
– вызывает setpgrp, чтобы оболочка выполнялась в своей группе процессов. Это позволяет оболочке полностью управлять обработкой сигналов, в особенности в отношении управления заданиями;
– вызывает системный вызов dup2 для перенаправления дескрипторов stdin, stdout и stderr на дескриптор файла ведомого устройства. Это особенно важный шаг;
– запускает оболочку при помощи вызова ехес, которая выполняется до тех пор, пока не будет прервана пользователем.
procedure runshell (sfd:longint);
begin
setpgrp;
dup2 (sfd, 0);
dup2 (sfd, 1);
dup2 (sfd, 2);
execl ('/bin/sh -i');
end;
Теперь рассмотрим саму процедуру script. Первым действием процедуры script является изменение дисциплины линии связи так, чтобы она работала в режиме прямого доступа. Это достигается получением текущих атрибутов терминала и изменением их при помощи вызова tcsetattr. Затем процедура script открывает файл output и использует системный вызов select (обсуждавшийся в главе 7) для обеспечения одновременного ввода со своего стандартного ввода и ведущего устройства псевдотерминала. Если данные поступают со стандартного ввода, то процедура script передает их без изменений ведущему устройству псевдотерминала. При поступлении же данных с ведущего устройства псевдотерминала процедура script записывает эти данные в терминал пользователя и в файл
output.
procedure script(mfd:longint);
var
nread, ofile:longint;
_set, master:fdset;
attr:termios;
buf:array [0..511] of char;
begin
(* Перевести дисциплину линии связи в режим прямого доступа *)
tcgetattr (0, attr);
attr.c_cc[VMIN] := 1;
attr.c_cc[VTIME] := 0;
attr.c_lflag := attr.c_lflag and not (ISIG or ECHO or ICANON);
tcsetattr (0, TCSAFLUSH, attr);
(* Открыть выходной файл *)
ofile := fdopen ('output', Open_CREAT or Open_WRONLY or Open_TRUNC, octal(0666));
(* Задать битовые маски для системного вызова select *)
FD_ZERO (master);
FD_SET (0, master);
FD_SET (mfd, master);
(* Вызов select осуществляется без таймаута,
* и будет заблокирован до наступления события. *)
_set := master;
while select (mfd + 1, @_set, nil, nil, nil) > 0 do
begin
(* Проверить стандартный ввод *)
if FD_ISSET (0, _set) then
begin
nread := fdread (0, buf, 512);
fdwrite (mfd, buf, nread);
end;
(* Проверить главное устройство *)
if FD_ISSET (mfd, _set) then
begin
nread := fdread (mfd, buf, 512);
write (ofile, buf, nread);
write (1, buf, nread);
end;
_set := master;
end;
end;
Следующий сеанс демонстрирует работу программы tscript. Комментарии, обозначенные символом #, показывают, какая из оболочек выполняется в данный момент.
$ ./tscript
$ ls -l tscript # работает новая оболочка
-rwxr-xr-x 1 spate fcf 6984 Jan 22 21:57 tscript
$ head -2 /etc/passwd # выполняется в новой оболочке
root:х:0:1:0000-Admin(0000):/:/bin/ksh
daemon:x:1:1:0000-Admin(0000):/:
$ exit # выход из новой оболочки
$ cat output # работает исходная оболочка
-rwxr-xr-x 1 spate fcf 6984 Jan 22 21:57 tscript
root:х:0:1:0000-Admin(0000):/:/bin/ksh
daemon:x:1:1:0000-Admin(0000):/:
Упражнение 9.5. Добавьте к программе обработку ошибок и возможность задания в качестве параметра имени выходного файла. Если имя не задано, используйте по умолчанию имя output.
Упражнение 9.6. Эквивалентная стандартная программа UNIX script позволяет задать параметр -а, который указывает на необходимость дополнения файла output (содержимое файла не уничтожается). Реализуйте аналогичную возможность в программе tscript.
Пример восстановление прежнего действия
Как упоминалось выше, в структуре sigaction может быть заполнен третий параметр oact. Это позволяет сохранять и восстанавливать прежнее состояние обработчика сигнала, как показано в следующем примере:
uses linux;
var
act, oact: sigactionrec;
(* Сохранить старый обработчик сигнала SIGTERM *)
sigaction(SIGTERM, nil, @oact);
(* Определить новый обработчик сигнала SIGTERM *)
act.handler.sh := SIG_IGN;
sigaction(SIGTERM, @act, nil);
(* Выполнить какие-либо действия *)
(* Восстановить старый обработчик *)
sigaction(SIGTERM, @oact, nil);
. Приоритеты процессов
Система приближенно вычисляет долю процессорного времени, отводимую для работы процесса, руководствуясь значением
nice (буквально «дружелюбный»). Значения nice находятся в диапазоне от нуля до максимального значения, зависящего от конкретной системы. Чем больше это число, тем ниже приоритет процесса. Процессы, «дружелюбно настроенные», могут понижать свой приоритет, используя системный вызов nice. Этот вызов имеет один аргумент, положительное число, на которое увеличивается текущее значение nice, например:
nice(5);
Процессы суперпользователя (и только суперпользователя) могут увеличивав свой приоритет, используя отрицательное значение параметра вызова nice. Вызов nice может пригодиться, если есть необходимость, например, вычислить число ? с точностью до ста миллионов знаков, не изменяя существенно время реакции системы для остальных пользователей. Вызов nice был введен давно. Современные факультативные расширения реального времени стандарта POSIX
определяют гораздо более точное управление планированием параллельной работы процессов.
Процедура sprintf
Прежде всего нужно отметить еще один момент, касающийся процедуры sprintf. Дело в том, что не следует думать о процедуре sprintf как о процедуре вывода. На самом деле она представляет собой наиболее гибкую из библиотечных процедур, работающих со строками и преобразующих форматы данных. Следующий текст показывает использование этой функции:
(* Процедура genkey - генерация ключа базы данных *)
uses stdio;
(* Длина ключа всегда будет равна 20 символам *)
function genkey (buf:pchar; const suppcode:pchar; orderno:longint):pchar;
begin
(* Проверка размера ключа *)
if strlen (suppcode) <> 10 then
begin
genkey:=nil;
exit;
end;
sprintf (buf, '%s_%.9d', [suppcode, orderno]);
genkey:=buf;
end;
var
buf:array [0..99] of char;
begin
if genkey (buf, 'supplement', 12)<>nil then
printf ('Key: %s'#$a, [pchar(buf)]);
end.
Тогда вызов процедуры genkey
printf('%s'#$a, [genkey(buf, 'abcdefghij', 12)]);
выведет такую строку ключа:
abcdefghij_000000012
Процедуры sigsetjmp и siglongjmp
Иногда при получении сигнала необходимо вернуться на предыдущую позицию в программе. Например, может потребоваться, чтобы пользователь мог вернуться в основное меню программы при нажатии клавиши прерывания. Это можно выполнить, используя две специальные функции sigsetjmp и siglongjmp. (Существуют альтернативные функции setjmp и longjmp, но их нельзя использовать совместно с обработкой сигналов.) Процедура sigsetjmp «сохраняет» текущие значения счетчика команд, позиции стека, регистров процессора и маски сигналов, а процедура siglongjmp передает управление назад в сохраненное таким образом положение. В этом смысле процедура siglongjmp аналогична оператору goto. Важно понимать, что возврат из процедуры siglongjmp не происходит, так как стек возвращается в сохраненное состояние. Как будет показано ниже, при этом происходит выход из соответствующего вызова sigsetjmp.
Процесс
В терминологии UNIX термин процесс (process) обычно обозначает экземпляр выполняющейся программы. Простейший способ создания процесса - передать команду для исполнения оболочке
(shell), которая также называется командным интерпретатором (command processor). Например, если пользователь напечатает:
$ ls
то процесс оболочки создаст другой процесс, в котором будет выполняться программа ls, выводящая список файлов в каталоге. UNIX – многозадачная система, поэтому несколько процессов могут выполняться одновременно. Фактически для каждого пользователя, работающего в данный момент с системой UNIX, выполняется хотя бы один процесс.
Программа etest
(* Программа etest - ввод имен объектов в очередь. *)
{$mode objfpc}
uses ipc,linux,stdio,sysutils;
{$i q.inc}
var
priority:longint;
begin
if paramcount <> 2 then
begin
writeln(stderr, 'Применение: ',paramstr(0),' имя приоритет');
halt (1);
end;
try
priority:=strtoint(paramstr(2));
except
on e:econverterror do
begin
warn ('Нечисловой приоритет');
halt (2);
end;
end;
if (priority <= 0) or (priority > MAXPRIOR) then
begin
warn ('Недопустимый приоритет');
halt (2);
end;
if not enter (paramstr(1), priority) then
begin
warn ('Ошибка в процедуре enter');
halt (3);
end;
halt (0);
end.
Программа io
В качестве очень простого примера использования стандартных дескрипторов файлов приведем программу io, применяющую системные вызовы fdread и fdwrite и дескрипторы файлов со значениями 0 и 1 для копирования стандартного ввода в стандартный вывод. В сущности, это усеченная версия программы UNIX cat. Обратите внимание на отсутствие вызовов fdopen и fdcreat.
(* Программа io копирует стандартный ввод *)
(* в стандартный вывод *)
uses linux;
const
SIZE=512;
var
nread:longint;
buf:array [0..SIZE-1] of byte;
begin
nread := fdread (0, buf, SIZE);
while nread > 0 do
begin
fdwrite (1, buf, nread);
nread := fdread (0, buf, SIZE);
end;
halt(0);
end.
Предположим, что исходный код этой программы находится в файле iо.pas, который компилируется для получения исполняемого файла io:
$ fpc io.pas
Если теперь запустить программу io на выполнение, просто набрав имя файла программы, то она будет ожидать ввода с терминала. Если пользователь напечатает строку и затем нажмет клавишу Return
или Enter на клавиатуре, то программа iо просто выведет на дисплей напечатанную строку, то есть запишет строку в стандартный вывод. При этом диалог с системой в действительности будет выглядеть примерно так:
$ io Пользователь печатает io и нажимает Return
Это строка 1 Пользователь печатает строку и нажимает Return
Это строка 1 Программа io
выводит строку на дисплей
.
.
.
После вывода строки на экран программа io будет ожидать дальнейшего ввода. Пользователь может продолжать печатать, и программа io
будет послушно выводить каждую строку на экран при нажатии на клавишу Return или Enter.
Для завершения программы пользователь может напечатать строку из единственного символа конца файла. Обычно это символ ^D, то есть Ctrl+D, который набирается одновременным нажатием клавиш Ctrl и D. При этом вызов fdread вернет 0, указывая на то, что достигнут конец файла. Весь диалог с системой мог бы выглядеть примерно так:
$ io
Это строка 1
Это строка 1
Это строка 2
Это строка 2
<Ctrl-D> Пользователь печатает Ctrl+D
$
Обратите внимание, что программа io ведет себя не совсем так, как можно было бы ожидать. Вместо того чтобы считать все 512 символов до начала вывода на экран, как, казалось бы, следует делать, она выводит строку на экран при каждом нажатии клавиши Return. Это происходит из-за того, что вызов fdread, который использовался для ввода данных с терминала, обычно возвращает значение после каждого символа перевода строки для облегчения взаимодействия с пользователем. Если быть еще более точным, это будет иметь место только для обычных настроек терминала. Терминалы могут быть настроены в другом режиме, позволяя осуществлять, например, посимвольный ввод. Дополнительные соображения по этому поводу изложены в главе 9.
Поскольку программа io
использует стандартные дескрипторы файлов, к ней можно применить стандартные средства оболочки для перенаправления и организации конвейеров. Например, выполнение команды
$ io < /etc/motd > message
приведет к копированию при помощи программы io сообщения с цитатой дня команды /etc/motd в файл message, а выполнение команды
$ io < /etc/motd | wc
направит стандартный вывод программы io в утилиту UNIX для подсчета числа слов wc. Так как стандартный вывод программы io
будет фактически идентичен содержимому /etc/motd, это просто еще один (более громоздкий) способ подсчета слов, строк и символов в файле.
Упражнение 2.15. Напишите версию программы io, которая проверяет наличие аргументов командной строки. Если существует хотя бы один из них, то программа должна рассматривать каждый из аргументов как имя файла и копировать содержимое каждого файла в стандартный вывод. Если аргументы командной строки отсутствуют, то ввод должен осуществляться из стандартного ввода. Как должна действовать программа io, если она не может открыть файл?
Упражнение 2.16. Иногда данные в файле могут медленно накапливаться в течение продолжительного промежутка времени. Напишите версию программы io с именем watch, которая будет выполнять чтение из стандартного ввода до тех пор, пока не встретится символ конца файла, выводя данные на стандартный вывод. После достижения конца файла программа watch должна сделать паузу на пять секунд, а затем снова начать чтение стандартного ввода, чтобы проверить, не поступили ли новые данные, не открывая при этом файл заново и не изменяя положение указателя чтения-записи. Для прекращения работы процесса на заданное время вымажете использовать стандартную библиотечную процедуру delay, которая имеет единственный аргумент – целое число, задающее продолжительность ожидания в миллисекундах. Например, вызов
sleep(5000);
заставляет процесс прекратить работу на 5 секунд. Программа watch аналогична программе readslow, существующей в некоторых версиях UNIX. Посмотрите также в руководстве системы описание ключа -f команды tail.