Выбрать главу

#include <assert.h>

#include <dirent.h>

#include <fcntl.h>

#include <grp.h>

#include <pwd.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <sys/uio.h>

#include <unistd.h>

#include "server.h"

/* Эта функция записывает в аргументы UID и GID

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

   принадлежит процесс с указанным идентификатором,

   в случае успешного завершения возвращается нуль,

   иначе -- ненулевое значение. */

static int get_uid_gid(pid_t pid, uid_t* uid, gid_t* gid) {

 char dir_name[64];

 struct stat dir_info;

 int rval;

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

    в файловой системе /proc. */

 snprintf(dir_name, sizeof(dir_name), "/proc/%d", (int)pid);

 /* Получение информации о каталоге. */

 rval = stat(dir_name, &dir_info);

 if (rval != 0)

  /* Каталог не найден. Возможно, процесс больше

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

  return 1;

 /* Убеждаемся в том, что это действительно каталог. */

 assert(S_ISDIR(dir_info.st_mode));

 /* Определяем интересующие нас идентификаторы. */

 *uid = dir_info.st_uid;

 *gid = dir_info.st_gid;

 return 0;

}

/* Эта функция находит имя пользователя,

   соответствующее заданному идентификатору.

   Возвращаемый буфер должен быть удален

   в вызывающей функции. */

static char* get_user_name(uid_t uid) {

 struct passwd* entry;

 entry = getpwuid(uid);

 if (entry == NULL)

  system_error("getpwuid");

 return xstrdup(entry->pw_name);

}

/* Эта функция находит имя группы, соответствующее

   заданному идентификатору, возвращаемый буфер

   должен быть удален в вызывающей функции. */

static char* get_group_name(gid_t gid) {

 struct group* entry;

 entry = getgrgid(gid);

 if (entry == NULL)

  system_error("getgrgid");

 return xstrdup(entry->gr_name);

}

/* Эта функция находит имя программы, которую выполняет

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

   должен быть удален в вызывающей функции. */

static char* get_program_name(pid_t pid) {

 char file_name[64];

 char status_info[256];

 int fd;

 int rval;

 char* open_paren;

 char* close_paren;

 char* result;

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

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

    и открываем этот файл. */

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

  (int)pid);

 fd = open(file_name, O_RDONLY);

 if (fd == 1)

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

     больше не существует. */

  return NULL;

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

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

 close(fd);

 if (rval <= 0)

  /* По какой-то причине файл не удалось прочитать, завершаем

     работу. */

  return NULL;

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

 status_info[rval] = '\0';

 /* Имя программы -- это второй элемент файла, заключенный в

    круглые скобки. Находим местоположение скобок. */

 open_paren = strchr(status_info, '(');

 close_paren = strchr(status_info, ')');

 if (open_paren == NULL ||

  close_paren == NULL || close_paren < open_paren)

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

  return NULL;

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

 result = (char*)xmalloc(close_paren — open_paren);

 /* Копирование имени программы в буфер. */

 strncpy(result, open_paren + 1, close_paren - open_paren — 1);

 /* Функция strncpy() не завершает строку нулевым символом,

    приходится это делать самостоятельно. */

 result[close_paren - open_paren - 1] = '\0';

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

 return result;

}

/* Эта функция определяет размер (в килобайтах) резидентной

   части процесса с заданным идентификатором.

   В случае ошибки возвращается -1. */

static int get_rss(pid_t pid) {