Материал: 6262

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

21 необходимо анализировать переменную errno.

Если данные нужно поместить в файл с нужной позиции, то предварительно нужно использовать системный вызов , который мы рассмотрим в следующем под-пункте данного подраздела.

Дополнительно, на результат вывода могут влиять различные системные ограничения ОС, например, максимальный размер файлов, поддерживаемых той или иной файловой системой. Ряд таких значений можно посмотреть с помощью утилиты prlimit, которая позволяет как получать так и устанавливать ряд лимитов процессов ОС.

Замечание

На рисунке 1.6 показаны текущие ресурсы процессов ОС УПК АСУ, полученные с помощью утилиты prlimit. Студенту не разрешается менять эти лимиты.

Рисунок 1.6 — Список лимитов ОС УПК АСУ

Демонстрацию применения изученных в данном подразделе системных функций проведем на примере задачи «Чтение и анализ структуры MBR». Напомним, что MBR является заголовочной структурой каждого накопителя типа «винчестер», совместимая с функциональными возможностями BIOS ЭВМ.

В новых системах, которые cодерживают UEFI вместо BIOS, возможна поддержка накопителей со структурой GPT, куда MBR входит как вспомогательная структура, предназначенная для защиты блочного устройства.

22

Для наших целей, структуру MBR можно представить таблицей:

Смещение (offset) Размер (Size) Содержимое (contents)

------------------------------------------------------------------------

0

446

Программа анализа

таблицы разделов

 

 

и

загрузки System

Bootstrap

 

 

с

активного раздела

-------------------------------------------------------------------------

0x1BE 16 Partition 1 entry (первый раздел)

-------------------------------------------------------------------------

0x1CE 16 Partition 2 entry

-------------------------------------------------------------------------

0x1DE 16 Partition 3 entry

-------------------------------------------------------------------------

0x1EE 16 Partition 4 entry

-------------------------------------------------------------------------

0x1FE 2 Сигнатура 0xAA55

Из таблицы видно, что MBR содержит 6 основных частей:

код System Bootstrap — 446 байт;

четыре описателя разделов по 16 байт;

сигнатуру MBR — 2 байта.

Поскольку сектор устройства типа «винчестер» имеет размер сектора равным 512 байт, а MBR расположен в первом секторе устройства (LBA0), то можно напи-сать программу, представленную на листинге 1.2, которая:

использует первый аргумент как имя исследуемого устройства;

открывает это устройство только для чтения;

записывает первый сектор устройства в буфер размерностью 512 байт;

проверяет наличие сигнатуры MBR;

выводит результаты анализа сектора на экран терминала.

Листинг 1.2 - Чтение MBR с заданного устройства и контроль ее структуры

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <linux/hdreg.h> #include <fcntl.h> #include <sys/types.h> #include <errno.h>

int main(int argc, char *argv[], char *envp[]) {

printf("Число параметров программы lab1.2: argc=%i\n", argc); if(argc < 2) { // Нет аргумента - завершаем работу

puts("Запусти: sudo ./lab1.2 /dev/sda\n"); return 1;

}

printf("Исследуем устройство: %s\n", argv[1]); //Введем обозначение типов данных:

typedef unsigned char u8; typedef unsigned short u16;

//Структура MBR

typedef struct mbr_sector{ u8 code[446];

 

 

23

u8

pt1[16];

 

u8

pt2[16];

 

u8

pt3[16];

 

u8

pt4[16];

 

u16 msignature;

 

} type_mbr;

 

// Переменные программы

 

int sd;

 

// Дескриптор файла

ssize_t z;

// Количество считанных байт

char sector[512]; // Буфер чтения

type_mbr *mbr;

// Указатель на структуру

// Открываем устройство - только для чтения sd=open(argv[1],O_RDONLY);

if(sd < 0) {

// Если не открыто - завершаем работу

perror(argv[1]);

 

return 2;

 

}else{

 

printf("Открыт файл %s: с дескриптором = %d\n", argv[1], sd);

}

z = read(sd, sector, sizeof(sector));// Читаем сектор printf("Прочитали из LBA0 %d байт\n", (int)z); close(sd); // Закрываем файл

mbr = (type_mbr *)&sector[0];

if (mbr->msignature == 0xAA55){ // Проверяем сигнатуру сектора puts("Обнаружили сектор MBR\n");

}else{

puts("Не смогли прочитать сектор MBR\n");

}

puts("Завершили работу...");

return EXIT_SUCCESS;

}

Замечание

Запуск всех программ для работы с устройствами должен проводиться от имени пользователя root, иначе они будут завершаться из-за отсутствия прав доступа к этим устройствам.

Результат запуска программы, приведенной на листинге 1.2, в виртуальном терминале показан на рисунке 1.7:

программа имеет название lab1.2 и запускается от имени пользователя root;

она определяет наличие аргумента, задающего устройство /dev/sda;

затем читает сектор LBA0 и обнаруживает наличие сигнатуры MBR.

Функциональность нашей программы легко расширяется, если рассмотреть структуру записи таблицы Partition Table, представленную на листинге 1.3.

24

Рис. 1.7. Проверка наличия сигнатуры устройства /dev/sda

Листинг 1.3 - Структура записи Partition Table

struct pt_struct {

 

u8

bootable;

// флаг активности раздела (0 или 80H)

u8

start_part[3]; // координаты начала раздела (HxSxC)

u8

type_part;

// системный идентификатор - System ID

u8

end_part[3];

// координаты конца раздела (HxSxC)

u32

sect_before;

// число секторов перед разделом

u32

sect_total;

// размер раздела в секторах (число секторов в разделе)

};

 

 

Замечание

В настоящее время, не следует пользоваться содержимым массивов start_part[3] и end_part[3], поскольку нужно хорошо знать особенности контроллера ввода-выво-да, установленного на используемой ЭВМ.

Для решения посталенной задачи, в простейшем случае, нам достаточно значений bootable , type_part, sect_before и sect_total.

Необходимо также проверить размерность самой структуры записи, чтобы убедиться в правильности выводимых данных.

На листинге 1.4 представлен текст такой программы, которая распечатывает основные параметры таблицы Partition Table для заданного устройства.

Листинг 1.4 — Чтение структуры Partition Table

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <linux/hdreg.h> #include <fcntl.h> #include <sys/types.h> #include <errno.h>

25

int main(int argc, char *argv[], char *envp[]) {

printf("Число параметров программы lab1.3: argc=%i\n", argc); if(argc < 2) { // Нет аргумента - завершаем работу

puts("Запусти: sudo ./lab1.3 /dev/sda\n"); return 1;

}

printf("Исследуем устройство: %s\n", argv[1]);

// Введем обозначение типов данных: typedef unsigned char u8;

typedef unsigned short u16; typedef unsigned int u32; //Структура записи Partition Table typedef struct pt_struct {

u8

bootable;

//

флаг активности раздела (0 или 80H)

u8

start_part[3]; //

координаты начала раздела

(HxSxC)

u8

type_part;

//

системный идентификатор -

System ID

u8

end_part[3];

//

координаты конца раздела

(HxSxC)

u32 sect_before;

//

число секторов перед разделом

u32 sect_total;

//

размер раздела в секторах (число секторов в разделе)

} pt_struct;

// Проверяем размер структуры записи Partition Table

printf("Размер структуры pt_struct = %lu байт\n", sizeof(pt_struct)); if (sizeof(pt_struct) != 16) {

puts("Ошибка: размер структуры записи Partition Table не равен 16 байтам"); return 1;

}

// Переменные программы

int sd;

//

Дескриптор файла

ssize_t z;

//

Количество считанных байт

char sector[512]; //

Буфер чтения сектора

pt_struct * pt;

//

Указатель на запись Partition Table

u8 status = 0;

//

Рабочая переменная

u16 * ss;

//

Рабочая переменная

int i;

//

Индекс цикла

// Открываем устройство - только для чтения sd=open(argv[1],O_RDONLY);

if(sd < 0) { // Если не открыто - завершаем работу perror(argv[1]);

return 2; }else{

printf("Открыт файл %s: с дескриптором = %d\n", argv[1], sd);

}

//Читаем сектор LBA0

z = read(sd, sector, sizeof(sector)); printf("Прочитали LBA0=%d байт\n", (int)z); close(sd);

if (z < 512) {

puts("Ошибка: прочитали меньше 512 байт"); return 1;

}

//Проверяем сигнатуру

ss = (u16 *)&sector[510]; if (*ss == 0xAA55){

printf("Прочитали сектор MBR: сигнатура = 0x%x\n", *ss); }else{

printf("Ошибка: Это не сектор MBR: сигнатура = 0x%x\n", *ss); return 1;

Источник: https://studfile.net/preview/16438530/