file.out
mmap.с
printdir
done.
Как это работает
Большинство операций сосредоточено в функции printdir. После некоторой начальной проверки ошибок с помощью функции opendir, проверяющей наличие каталога, printdirвыполняет вызов функции chdirдля заданного каталога. До тех пор пока элементы, возвращаемые функцией readdir, не нулевые, программа проверяет, не является ли очередной элемент каталогом. Если нет, она печатает элемент-файл с отступом, равным depth.
Если элемент — каталог, вы встречаетесь с рекурсией. После игнорирования элементов .и ..(текущего и родительского каталогов) функция printdirвызывает саму себя и повторяет весь процесс снова. Как она выбирается из этих повторений? Как только цикл whileзаканчивается, вызов chdir("..")возвращает программу вверх по дереву каталогов, и предыдущий перечень можно продолжать. Вызов closedir(dp)гарантирует, что количество открытых потоков каталогов не больше того, которое должно быть.
Для того чтобы составить представление об окружении в системе Linux, обсуждаемом в главе 4, познакомьтесь с одним из способов, повышающих универсальность программы. Рассматриваемая программа ограничена, потому что привязана каталогу /home. Следующие изменения в функции mainмогли бы превратить эту программу в полезный обозреватель каталогов:
int main(int argc, char* argv[]) {
char *topdir = ".";
if (argc >= 2) topdir = argv[1];
printf("Directory scan of %s\n", topdir);
printdir(topdir, 0);
printf("done.\n");
exit(0);
}
Три строки изменены и пять добавлено, но это уже универсальная утилита с необязательным параметром, содержащим имя каталога, по умолчанию равным текущему каталогу. Вы можете выполнять ее с помощью следующей командной строки:
$ ./printdir2 /usr/local | more
Вывод будет разбит на страницы, и пользователь сможет листать их. Таким образом, у него появится маленький удобный универсальный обозреватель дерева каталогов. Приложив минимум усилий, вы могли бы добавить статистический показатель использования пробелов, предельную глубину отображения и т.д.
Как вы видели, многие системные вызовы и функции, описанные в этой главе, могут завершиться аварийно по ряду причин. Когда это происходит, они указывают причину сбоя, задавая значение внешней переменной errno. Многие стандартные библиотеки используют эту переменную как стандартный способ оповещения о возникших проблемах. Стоит повторить, что программа должна проверять переменную errno сразу же после возникновения проблемы в функции, поскольку errno может быть изменена следующей вызванной функцией, даже если она завершилась нормально.
Имена констант и варианты ошибок перечислены в заголовочном файле errno.h. К ним относятся следующие:
□ EPERM— Operation not permitted (операция не разрешена);
□ ENOENT— No such file or directory (нет такого файла или каталога);
□ EINTR— Interrupted system call (прерванный системный вызов);
□ EIO— I/O Error (ошибка ввода/вывода);
□ EBUSY— Device or resource busy (устройство или ресурс заняты);
□ EEXIST— File exists (файл существует);
□ EINVAL— Invalid argument (неверный аргумент);
□ EMFILE— Too many open files (слишком много открытых файлов);
□ ENODEV— No such device (нет такого устройства);
□ EISDIR— Is a directory (это каталог);
□ ENOTDIR— Isn't a directory (это не каталог).
Есть пара полезных функций, сообщающих об ошибках при их возникновении: strerrorи perror.
Функция strerrorпреобразует номер ошибки в строку, описывающую тип возникшей ошибки. Она может быть полезна для регистрации условий, вызывающих ошибку.
Далее приведена ее синтаксическая запись:
#include
char *strerror(int errnum);
Функция perrorтакже превращает текущую ошибку в виде, представленном в переменной errno, в строку и выводит ее в стандартный поток ошибок. Ей предшествует сообщение, заданное в строке s(если указатель не равен NULL), за которым следуют двоеточие и пробел.
Далее приведена синтаксическая запись функции:
#include
void perror(const char *s);
Например, вызов
perror("program");
может дать следующий результат в стандартном потоке ошибок:
program: Too many open files
Ранее в этой главе мы уже писали о том, что ОС Linux обрабатывает многие вещи как файлы, и в файловой системе есть ряд элементов для аппаратных устройств. Эти файлы /dev применяются для доступа к оборудованию особыми методами с помощью низкоуровневых системных вызовов.
Читать дальше