KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Марк Митчелл - Программирование для Linux. Профессиональный подход

Марк Митчелл - Программирование для Linux. Профессиональный подход

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Марк Митчелл, "Программирование для Linux. Профессиональный подход" бесплатно, без регистрации.
Перейти на страницу:

 int rval;

 int rss;


 /* Генерируем имя файла "statm", находящегося в каталоге

    данного процесса в файловой системе proc. */

 snprintf(file_name, sizeof(file_name), "/proc/%d/statm",

  (int)pid);

 /* Открытие файла. */

 fd = open(file_name, O_RDONLY);

 if (fd == -1)

  /* Файл не удалось открыть. Возможно, процесс больше не

     существует. */

  return -1;

 /* Чтение содержимого файла. */

 rval = read(fd, mem_info, sizeof(mem_info) — 1);

 close(fd);

 if (rval <= 0)

  /* Файл не удалось прочитать, завершаем работу. */

  return -1;

 /* Завершаем прочитанный текст нулевым символом. */

 mem_infо[rval] = '';

 /* Определяем размер резидентной части процесса. Это второй

    элемент файла. */

 rval = sscanf(mem_info, "%*d %d", &rss);

 if (rval != 1)

  /* Содержимое файла statm отформатировано непонятным

     образом. */

  return -1;


 /* Значения в файле statm приведены в единицах, кратных размеру

    системной страницы. Преобразуем в килобайты. */

 return rss * getpagesize() / 1024;

}


/* Эта функция генерирует строку таблицы для процесса

   с заданным идентификатором. Возвращаемый буфер должен

   удаляться в вызывающей функции, в случае ошибки

   возвращается NULL. */

static char* format_process_info(pid_t pid) {

 int rval;

 uid_t uid;

 gid_t gid;

 char* user_name;

 char* group_name;

 int rss;

 char* program_name;

 size_t result_length;

 char* result;


 /* Определяем идентификаторы пользователя и группы, которым

    принадлежит процесс. */

 rval = get_uid_gid(pid, &uid, &gid);

 if (rval != 0)

  return NULL;

 /* Определяем размер резидентной части процесса. */

 rss = get_rss(pid);

 if (rss == -1)

  return NULL;

 /* Определяем имя исполняемого файла процесса. */

 program_name = get_program_name(pid);

 if (program_name == NULL)

  return NULL;

 /* Преобразуем идентификаторы пользователя и группы в имена. */

 user_name = get_user_name(uid);

 group_name = get_group_name(gid);

 /* Вычисляем длину строки, в которую будет помещен результат,

    и выделяем для нее буфер. */

 result_length =

  strlen(program_name) + strlen(user_name) +

  strlen(group_name) + 128;

 result = (char*)xmalloc(result_length);

 /* Форматирование результата. */

 snprintf(result, result_length,

  "<tr><td align=" right">%d</td><td><tt>%s</tt></td><td>%s</td>"

  "<td>%s</td><td align= "right">%d</td></tr>n",

  (int)pid, program_name, user_name, group_name, rss);

 /* Очистка памяти. */

 free(program_name);

 free(user_name);

 free(group_name);

 /* Конец работы. */

 return result;

}


/* HTML-код начала страницы, содержащей таблицу процессов. */

static char* page_start =

 "<html>n"

 " <body>n"

 "  <table cellpadding="4" cellspacing="0" border="1">n"

 "   <thead>n"

 "    <tr>n"

 "     <th>PID</th>n"

 "     <th>Program</th>n"

 "     <th>User</th>n"

 "     <th>Group</th>n"

 "     <th>RSS&nbsp;(KB)</th>n"

 "    </tr>n"

 "   </thead>n"

 "   <tbody>n";


/* HTML-код конца страницы, содержащей таблицу процессов. */

static char* page_end =

 "   </tbody>n"

 "  </table>n"

 " </body>n"

 "</html>n";

void module_generate(int fd) {

 size_t i;

 DIR* proc_listing;


 /* Создание массива iovec. В этот массив помещается выходная

    информации, причем массив может увеличиваться динамически. */


 /* Число используемых элементов массива */

 size_t vec_length = 0;

 /* выделенный размер массива */

 size_t vec_size = 16;

 /* Массив элементов iovec. */

 struct iovec* vec =

  (struct iovec*)xmalloc(vec_size *

  sizeof(struct iovec));


 /* Сначала в массив записывается HTML-код начала страницы. */

 vec[vec_length].iov_base = page_start;

 vec[vec_length].iov_len = strlen(page_start);

 ++vec_length;


 /* Получаем список каталогов в файловой системе /proc. */

 proc_listing = opendir("/proc");

 if (proc_listing == NULL)

  system_error("opendir");


 /* Просматриваем список каталогов. */

 while (1) {

  struct dirent* proc_entry;

  const char* name;

  pid_t pid;

  char* process_info;


  /* Переходим к очередному элементу списка. */

  proc_entry = readdir(proc_listing);

  if (proc_entry == NULL)

   /* Достигнут конец списка. */

   break;


  /* Если имя каталога не состоит из одних цифр, то это не

     каталог процесса; пропускаем его. */

  name = proc_entry->d_name;

  if (strspn(name, "0123456789") != strlen(name))

   continue;

  /* Именем каталога является идентификатор процесса. */

  pid = (pid_t)atoi(name);


  /* генерируем HTML-код для строки таблицы, содержащей

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

  process_info = format_process_info(pid);

  if (process_info == NULL)

   /* Произошла какая-то ошибка. Возможно, процесс уже

      завершился. Создаем строку-заглушку. */

   process_info =

    "<tr><td colspan="5">ERROR</td></tr>";

  /* Убеждаемся в том, что в массиве iovec достаточно места

     для записи буфера (один элемент будет добавлен в массив

     по окончании обработки списка процессов). Если места

     не хватает, удваиваем размер массива. */

  if (vec_length == vec_size - 1) {

   vec_size *= 2;

   vec = xrealloc(vec, vec_size - sizeof(struct iovec));

  }

  /* Сохраняем в массиве информацию о процессе. */

  vec[vec_length].iov_base = process_info;

  vec[vec_length].iov_len = strlen(process_info);

  ++vec_length;

 }


 /* Конец обработки списка каталогов */

 closedir(proc_listing);


 /* Добавляем HTML-код конца страницы. */

 vec[vec_length].iov_base = page_end;

 vec[vec_length].iov_len = strlen(page_end);

 ++vec_length;


 /* Передаем всю страницу клиенту. */

 writev(fd, vec, vec_length);

 /* Удаляем выделенные буферы. Первый и последний буферы

    являются статическими, поэтому не должны удаляться. */

 for (i = 1; i < vec_length - 1; ++i)

  free(vec[i].iov_base);

 /* Удаляем массив iovec. */

 free(vec);

}

Задача сбора информации о процессах и представления ее в виде HTML-таблицы разбивается на ряд более простых операций.

■ Функция get_uid_gid() возвращает идентификатор пользователя и группы, которым принадлежит процесс. Для этого вызывается функция stat() (описана в приложении Б, "Низкоуровневый ввод-вывод"), берущая информацию из каталога процесса в файловой системе /proc.

■ Функция get_user_name() возвращает имя пользователя, соответствующее заданному идентификатору. Она просто вызывает библиотечную функцию getpwuid(), которая обращается к файлу /etc/passwd и возвращает копию строки из него. Функция get_group_name() находит имя группы по заданному идентификатору. Она вызывает функцию getgrgid().

■ Функция gеt_program_name() возвращает имя программы, соответствующей заданному процессу. Эта информация извлекается из файла stat, находящегося в каталоге процесса в файловой системе /proc (см. раздел 7.2, "Каталоги процессов"). Мы поступаем так, а не проверяем символические ссылки exe или cmdline, поскольку последние недоступны, если серверный процесс не принадлежит тому же пользователю, что и проверяемый процесс.

■ Функция get_rss() определяет объем резидентной части процесса. Эта информация содержится во втором элементе файла statm (см. раздел 7.2.6, "Статистика использования процессом памяти"), находящегося в каталоге процесса в файловой системе /proc.

■ Функция format_process_info() генерирует набор HTML-тэгов для строки таблицы, представляющей заданный процесс. Здесь вызываются все вышеперечисленные функции.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*