Марк Митчелл - Программирование для Linux. Профессиональный подход
В Linux имеются функции, предназначенные для чтения содержимого каталога. И хотя они не относятся к низкоуровневым функциям, мы все же решили их описать, так как они широко применяются в программах.
При чтении содержимого каталога необходимо придерживаться такой последовательности действий.
1. Вызовите функцию opendir(), передав ей путевое имя требуемого каталога. Эта функция возвращает дескриптор типа DIR*, который можно использовать для доступа к содержимому каталога. В случае ошибки возвращается NULL.
2. Последовательно вызывайте функцию readdir(), передавая ей дескриптор, полученный от функции opendir(). Всякий раз функция readdir() будет возвращать указатель на структуру типа dirent, содержащую информацию о следующем элементе каталога. По достижении конца каталога будет получено значение NULL. У структуры dirent есть поле d_name, где содержится имя элемента каталога.
3. Вызовите функцию closedir(), передав ей имеющийся дескриптор, чтобы завершить сеанс работы с каталогом.
Для использования перечисленных функций необходимо включить в программу файлы <sys/types.h> и <dirent.h>. Ответственность за сортировку содержимого каталога возлагается на программу.
В листинге Б.8 показана программа отображающая список содержимого каталога. Имя каталога задается в командной строке. Если этого не сделать, будет проанализирован текущий каталог. Для каждого элемента каталога отображается его тип и путевое имя. Функция get_file_type() определяет тип объекта файловой системы с помощью функции lstat().
Листинг Б.8. (listdir.c) Вывод содержимого каталога#include <assert.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
/* Эта функция возвращает строку с описанием типа объекта
файловой системы, заданного в аргументе PATH. */
const char* get_file_type(const char* path) {
struct stat st;
lstat(path, &st);
if (S_ISLNK(st.st_mode))
return "symbolic link";
else if (S_ISDIR(st.st_mode))
return "directory";
else if (S_ISCHR(st.st_mode))
return "character device";
else if (S_ISBLK(st.st_mode))
return "block device";
else if (S_ISFIFO(st.st_mode))
return "fifo";
else if (S_ISSOCK(st.st_mode))
return "socket";
else if (S_ISREG(st.st_mode))
return "regular file";
else
/* Нераспознанный тип. */
assert(0);
}
int main(int argc, char* argv[]) {
char* dir_path;
DIR* dir;
struct dirent* entry;
char entry_path[PATH_MAX + 1];
size_t path_len;
if (argc >= 2)
/* Если каталог указан в командной строке, анализируем его. */
dir_path = argv[1];
else
/* В противном случае анализируем текущий каталог. */
dir_path = ".";
/* Копируем имя каталога в переменную entry_path. */
strncpy(entry_path, dir_path, sizeof(entry_path));
path_len = strlen(dir_path);
/* Если имя каталога не заканчивается косой чертой,
добавляем ее. */
if (entry_path[path_len - 1] != '/') {
entry_path[path_len] = '/';
entry_path[path_len + 1] = ' ';
++path_len;
}
/* Начинаем обрабатывать список содержимого каталога. */
dir = opendir(dir_path);
/* просматриваем все элементы каталога. */
while ((entry = readdir(dir)) != NULL) {
const char* type;
/* Формируем полное путевое имя элемента каталога. */
strncpy(entry_path + path_len, entry->d_name,
sizeof(entry_path) — path_len);
/* Определяем тип элемента. */
type = get_file_type(entry_path);
/* Отображаем собранную информацию. */
printf("%-18s: %sn", type, entry_path);
}
/* Конец работы. */
closedir(dir);
return 0;
}
Приведем несколько строк листинга полученного в каталоге /dev (в разных системах могут быть выданы разные результаты)
% ./listdir /dev
directory : /dev/.
directory : /dev/..
socket : /dev/log
character device : /dev/null
regular file : /dev/MAKEDEV
fifo : /dev/initctl
character device : /dev/agpgart
...
Для проверки этих данных можно воспользоваться командой ls. Флаг -U отменяет сортировку списка, а флаг -a заставляет включить в список записи текущего (.) и родительского (..) каталогов.
% ls -lua /dev total 124
drwxr-xr-x 7 root root 36864 Feb 1 15:14 .
drwxr-xr-x 22 root root 4096 Oct 11 16:39 ..
srw-rw-rw- 1 root root 0 Dec 18 01:31 log
crw-rw-rw- 1 root root 1, 3 May 5 1998 null
-rwxr-xr-x 1 root root 26689 Mar 2 2000 MAKEDEV
prw------- 1 root root 0 Dec 11 18:37 initctl
crw-rw-r-- 1 root root 10, 175 Feb 3 2000 agpgart
Первый символ каждой строки определяет тип элемента каталога.
Приложение В
Таблица сигналов
В табл. В.1 перечислены сигналы, которые чаще всего приходится обрабатывать в Linux-программах. Некоторые сигналы имеют разные интерпретации в зависимости от того, где они были получены.
Указанные имена сигналов определены в виде макроконстант препроцессора. Чтобы иметь возможность сослаться на них в программе необходимо подключить файл <signal.h>. Реальное определение сигналов дано в файле /usr/sys/signum.h, который подключается к файлу <signal.h>.
Для получения полного списка сигналов, поддерживаемых в Linux, необходимо выполнить такую команду:
% man 7 signal
Таблица В.1. Сигналы ОС Linux
Название Описание SIGHUP Linux посылает этот сигнал, когда происходит отключение от терминала. Многие программы применяют этот сигнал в совершенно иных целях: он служит указанием программе повторно прочитать свой файл конфигурации SIGINT Linux посылает процессу этот сигнал, когда пользователь пытается завершить процесс нажатием клавиш <Ctrl+C> SIGILL Процесс получает этот сигнал при попытке выполнить недопустимую инструкцию. Это может означать повреждение стека программы SIGABRT Этот сигнал посылается функцией abort() SIGFPE По течение этого сигнала означает, что процесс выполнил недопустимую операцию с плавающей запятой. В зависимости от конфигурации центрального процессора результатом операции может стать специальное нечисловое значение, например inf (бесконечность) или NaN (не число), а не сигнал SIGFPE SIGKILL Этот сигнал приводит к немедленному завершению процесса и не может быть перехвачен SIGUSR1 Этот сигнал зарезервирован для прикладного использования SIGUSR2 Этот сигнал зарезервирован для прикладного использования SIGSEGV Этот сигнал означает, что программа выполнила недопустимое обращение к памяти. Возможно, указанный адрес находится за пределами адресного пространства процесса или процессу запрещен доступ к этому участку памяти SIGPIPE Этот сигнал означает, что программа обратилась к разрушенному потоку данных, например к сокету, который был закрыт на противоположной стороне SIGALRM Доставка этого сигнала планируется функциями alarm() и setitimer() (см. раздел 8.13 "Функция setitimer(): задание интервальных таймеров") SIGTERM Этот сигнал является запросом на завершение процесса и посылается командой kill по умолчанию SIGCHLD Linux посылает процессу этот сигнал при завершении одного из дочерних процессов (см. раздел 3.4.4, "Асинхронное удаление дочерних процессов") SIGXCPU Linux посылает процессу этот сигнал в случае превышения разрешенного времени доступа к центральному процессору (см. раздел 8.5, "Функции getrlimit() и setrlimit(): лимиты ресурсов") SIGVTALRM Доставка этого сигнала планируется функцией setitimer() (см. раздел 8.13, "Функция setitimer(): задание интервальных таймеров")Приложение Г