Двоичные журналы - часть 2
Все программы операционной системы, читающие и пишущие в файл wtmp, берут определение файла из одного коротенького включаемого файла С, который скорее всего расположен в /usr/include/utmp.h. Интересующая нас часть файла начинается с определения структуры данных С, которая будет использоваться для хранения информации. Если мы поищем struct utmp {, то найдем нужную нам часть. Строки, следующие за struct utmp {, определяют каждое поле этой структуры. Каждая из этих строк сопровождается комментарием в стиле /* се/ .
Чтобы почувствовать, насколько могут отличаться две различные версии wtmp, сравним отрывки из uimp.h для двух операционных систем:
SunOS 4.1.4:
struct utmp {
char ut_line[8]; /* tty name */
cnar ut_name[8]; /* user id «/
char ut__host[16]: /* nost name, if remote •/
long ut_tiine; /'* time on */ }:
Digital Unix 4.0:
slr.ict jT^ip !
В этих файлах есть все, что требуется для написания функции unpack(), которая в качестве первого аргумента принимает шаблон формата данных и с помощью этого шаблона определяет, как разобрать двоичные (обычно) данные, переданные во втором аргументе. unpack() разобьет данные так, как это указано, и вернет список, каждый элемент которого соответствует элементу шаблона.
Давайте построим шаблон по кусочкам, принимая за основу структуру на С из файла utmp.h в SunOS. Многие буквы разрешается использовать в шаблонах и здесь рассказывается именно о них, но вообще-то вы должны обратиться к разделу pack() из руководстваperlfunc за подробными разъяснениями. Создание шаблонов - не всегда простое занятие; периодически компиляторы С дополняют поля структуры для того, чтобы выровнять их по требуемой границе памяти. Команда pstruct, входящая в состав Perl, часто помогает справиться с подобными особенностями.
С нашим форматом данных таких сложностей не возникает. Посмотрите на анализ файла utmp.h (табл. 9.1).
Таблица 9.1. Преобразование кода на С из utmp.h в шаблон unpack( )
Код на С |
Шаблон unpack() |
Буква шаблона/повтор |
char ut_line[8]; |
A8 |
Строка ASCII (дополнена пробелами) длиной 8 байт |
char ut_name[8]; |
A8 |
Строка ASCII (дополнена пробелами) длиной 8 байт |
char ut_host[16]; |
A16 |
Строка ASCII (дополнена пробелами) длиной 16 байт |
long ut_time; |
1 |
«Длинное» целое значение со знаком (может и не совпадать с размером значения «long» на конкретной машине) |