167       который мы, возможно, добавили в main. */

168    /* Вывести все до добавленной нами части. */

169    fwrite(file, arg_length, 1, stdout);

170    /* Вывести все после добавленного нами. */

171    fputs(file + arg_length + suffix_length

172     + (file[arg_length + suffix_length] == '/'), stdout);

173   }

174   else

175   {

176    fputs(file, stdout);

177   }

178   fputc('\n', stdout);

179   fflush(stdout);

180  }

181

182  return 0;

183 }

Условие в строках 158–160 сбивает с толку, и комментарий в строке 157 указывает на это. Условие утверждает: «Если (1a) файл является каталогом и (1b) уровень меньше максимального для вывода (переменные — -max-depth и max_depth) или нулевой, или (2a) должны быть выведены все файлы и уровень меньше, чем максимальный для вывода, или (2b) уровень нулевой», тогда вывести файл. (Версия du после 5.0 использует в этом случае несколько менее запутанное условие.)

Строки 162–179 осуществляют вывод. Строки 162–163 выводят размер и символ TAB Строки 164–173 обрабатывают специальный случай. Это объяснено далее в du.c, в строках файла 524–529:

524 /* При разыменовании лишь аргументов командной строки мы

525    используем флаг nftw FTW_PHYS, поэтому символическая ссылка

526    на каталог, указанная в командной строке, в норме не

527    разыменовывается. Для решения этого мы идем на издержки,

528    сначала добавляя '/.' (или '.'), а затем удаляем их каждый раз

529    при выводе имени производного файла или каталога. */

В этом случае arg_length равен true, поэтому строки 164–173 должны вывести первоначальное имя, а не измененное В противном случае строки 174–177 могут вывести имя как есть.

Фу! Куча кода. Мы находим, что это верхний уровень спектра сложности, по крайней мере, насколько это может быть просто представлено в книге данного содержания. Однако, он демонстрирует, что код из реальной жизни часто бывает сложным. Лучшим способом справиться с этой сложностью является ясное именование переменных и подробные комментарии du.с в этом отношении хорош; мы довольно легко смогли извлечь и изучить код без необходимости показывать все 735 строк программы!

<p>8.6. Изменение корневого каталога: <code>chroot()</code></p>

Текущий рабочий каталог, установленный с помощью chdir() (см. раздел 8.4.1 «Изменение каталога — chdir() и fchdir()»), является атрибутом процесса, таким же, как набор открытых файлов. Он также наследуется новыми процессами.

Менее известным является то, что у каждого процесса есть также текущий корневой каталог. Это именно на этот каталог ссылается имя пути /. В большинстве случаев корневые каталоги процесса и системы идентичны. Однако, суперпользователь может изменить корневой каталог с помощью (как вы догадались) системного вызова chroot():

#include /* Обычный */

int chroot(const char *path);

Возвращаемое значение равно 0 при успешном завершении и -1 при ошибке.

Как указывает справочная страница GNU/Linux chroot(2), изменение корневого каталога не изменяет текущий каталог: программы, которые должны обеспечить нахождение под новым корневым каталогом, должны также вызвать затем chdir():

if (chroot("/new/root") < 0) /* Установить новый корневой каталог */

 /* обработать ошибку */

if (chdir("/some/dir") < 0) /* Пути даны не относительно нового корневого каталога */

 /* обработать ошибку */

Перейти на страницу:

Похожие книги