11.3.3. Отображение объема свободного дискового пространства

11.3.3. Отображение объема свободного дискового пространства

Модуль diskfree.so (исходный текст приведен в листинге 11.8) генерирует страницу с информацией о свободном дисковом пространстве в файловых системах, смонтированных на серверном компьютере. Эта информация берется из выходных данных команды df -h. Как и в модуле issue.so, выходные данные заключаются в тэги <pre></pre>.

Листинг 11.8. (diskfree.c) Серверный модуль, отображающий информацию о свободном дисковом пространстве

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <unistd.h>

#include "server.h"

/* HTML-код начала генерируемой страницы. */

static char* page_start =

 "<html> "

 " <body> "

 "  <pre> ";

/* HTML-код конца генерируемой страницы. */

static char* page_end =

 "  </pre> "

 " </body> "

 "</html> ";

void module_generate(int fd) {

 pid_t child_pid;

 int rval;

 /* Запись начала страницы. */

 write(fd, page_start, strlen(page_start));

 /* Создание дочернего процесса. */

 child_pid = fork();

 if (child_pid == 0) {

  /* Это дочерний процесс. */

  /* Подготовка списка аргументов команды df. */

  char* argv[] = { "/bin/df, "-h", NULL };

  /* Дублирование потоков stdout и stderr для записи данных

     в клиентский сокет. */

  rval = dup2(fd, STDOUT_FILENO);

  if (rval == -1)

   system_error("dup2");

  rval = dup2(fd, STDERR_FILENO);

  if (rval == -1)

   system_error("dup2");

  /* Запуск команды df, отображающей объем свободного

     пространства в смонтированных файловых системах. */

  execv(argv[0], argv);

  /* Функция execv() возвращает управление в программу только

     при возникновении ошибки. */

  system_error("execv");

 } else if (child_pid > 0) {

  /* Это родительский процесс, дожидаемся завершения дочернего

     процесса. */

  rval = waitpid(child_pid, NULL, 0);

  if (rval == -1)

   system_error("waitpid");

 } else

  /* Вызов функции fork() завершился неудачей. */

  system_error("fork");

 /* запись конца страницы. */

 write(fd, page_end, strlen(page_end));

}

В то время как модуль issue.so посылает содержимое файла с помощью функции sendfile(), данный модуль должен вызвать внешнюю команду и перенаправить результаты ее работы клиенту. Для этого модуль придерживается такой последовательности действий.

1. Сначала с помощью функции fork() создается дочерний процесс (см. раздел 3.2.2. "Функции fork() и exec()").

2. Дочерний процесс копирует дескриптор сокета в дескрипторы STDOUT_FILENO и STDERR_FILENO, соответствующие стандартным потокам вывода и ошибок (см. раздел 2.1.4, "Стандартный ввод-вывод"). Это копирование осуществляется с помощью системного вызова dup2() (см. раздел 5.4 3. "Перенаправление стандартных потоков ввода, вывода и ошибок"). Все последующие данные, записываемые в эти потоки в рамках дочернего процесса, будут направляться в сокет.

3. Дочерний процесс с помощью функции execv() вызывает команду df -h.

4. Родительский процесс дожидается завершения дочернего процесса, вызывая функцию waitpid() (см. раздел 5.4 2. "Системные вызовы wait()").

Этот модуль можно легко настроить на вызов другой системной команды.