Linux программирование
Управление хранением данных на диске – одна из самых важных задач любой ОС, настолько важных, что система DOS так и называлась – дисковая операционная система. Вероятно, читатель этой статьи, желающий стать Linux- программистом, уже знает, как устроена файловая система Linux с точки зрения пользователя. Мы рассмотрим эту систему с точки зрения программиста. Один из основополагающих принципов Unix/Linux – everything is a file – в вольном переводе означает: «файлы - наше все».
Linux отображает в виде файлов не только сами файлы, но и различные типы установленных в системе устройств, а также некоторые структуры данных, создаваемые в ходе работы. Возможность управлять устройством как файлом существенно упрощает решение некоторых задач, однако, во многих случаях файловый интерфейс – не самый удобный и параллельно с ним существуют другие типы программных интерфейсов для работы с устройствами. Стандартная библиотека Linux glibc предоставляет нам полный набор функций для работы с файлами, а точнее даже два полных набора – системные вызовы Linux и реализованные на их основе функции стандартной библиотеки C (прежде, чем приступать к изучению примеров из этой статьи, рекомендуется ознакомиться с документацией к этой библиотеке).
Может показаться, что системные вызовы более эффективны, чем библиотечные функции, но это не так. Как правило, чем меньше системных вызовов, тем быстрее будет работать ваша программа. Дело в том, что для выполнения своей работы системные вызовы переключают систему в режим ядра, а затем возвращаются в пользовательский режим. В прежних версиях переключение осуществлялось с помощью прерывания int 80h, в новых, где указана архитектура i686, - с помощью специальной процессорной команды, появившейся в Pentium II [1]. Переключение между режимами занимает сравнительно много процессорного времени, поэтому библиотечные функции минимизируют количество системных вызовов, заставляя каждый такой вызов выполнять как можно больше полезной работы. И системные вызовы и функции стандартной библиотеки C экспортируются библиотекой glibc. Функции для работы с файлами open(), close(), read(), write() и им подобные, использующие дескрипторы файлов, представляют собой обертки для соответствующих системных вызовов. Функции fopen(), fclose(), fread(), fwrite(), fseek(), и другие, работающие со структурой FILE, - являются частью стандартной библиотеки.
Особую роль среди системных вызовов играет вызов ioctl(2), являющийся, фактически, универсальным средством управления устройствами, представленными в виде файлов (за универсальность вызов ioctl() называют швейцарским армейским ножом). Первым параметром функции ioctl() должен быть дескриптор открытого файла. Второй параметр – запрос или команда. Помимо этого, при вызове ioctl() могут передаваться дополнительные параметры, число и типы которых зависят от значения второго параметра функции. Функция ioctl() возвращает результаты вызова в переменных, переданных по ссылке ли через стек (в виде результата функции). Следует отметить, что в последнее время среди разработчиков Linux наметилась тенденция на отказ от использования ioctl(). Мы не будем останавливаться на классических примерах работы с файлами, а рассмотрим несколько примеров, специфичных именно для Unix/Linux.