Linux

Linux API для отображения запущенных процессов

Мне нужен C/C++ API, который позволит мне перечислить запущенные процессы в системе Linux, а также перечислить файлы, открытые каждым процессом. Я не хочу в конечном итоге читать файловую систему /proc/ напрямую. Кто-нибудь может предложить способ сделать это?

Ответ 1

Если вы не хотите читать из '/proc, тогда вы можете рассмотреть возможность написания модуля Kernel, который будет реализовывать ваш собственный системный вызов. И ваш системный вызов должен быть написан так, чтобы он мог получить список текущих процессов, например:

/* ProcessList.c  */

    #include < linux/kernel.h >

    #include < linux/sched.h >

    #include < linux/module.h >

    int init_module(void) {

        struct task_struct *task;

        for_each_process(task) {

              printk("%s [%d]\n",task->comm , task->pid);

        }

        return 0;

    }

    void cleanup_module(void) {

        printk(KERN_INFO "Cleaning Up.\n");

    }

 Приведенный выше код взят из моей статьи здесь http://linuxgazette.net/133/saha.html. Теперь у вас есть свой собственный системный вызов, вы можете вызывать его из программы пространства пользователя. 

Ответ 2

Вот, пожалуйста, код на C/C++. Вы могли бы найти его здесь: http://ubuntuforums.org/showthread.php?t=657097

По сути, он перебирает все числовые папки в /proc/<pid>, а затем выполняет readlink на /proc/<pid>/exe, или, если вам нужны аргументы командной строки, cat /proc/<pid>/cmdline.

Дескрипторы файлов, открытых процессом, находятся в /proc/<pid>/fd/<descriptor>, и вы получаете имя файла, выполняя readlink на каждом симлинке, например: readlink /proc/<pid>/fd/<descriptor>. fd может быть устройством, таким как /dev/null, сокетом или файлом.б

#include <unistd.h>

ssize_t readlink(const char *path, char *buf, size_t bufsiz);

В случае успеха readlink() возвращает количество байт, помещенных в buf. При ошибке возвращается -1 и устанавливается значение errno, указывающее на ошибку.

Это, кстати, то же самое, что делает (или, по крайней мере, делал) readproc.c.

Конечно, надеюсь, они сделали это без возможности переполнения буфера.

#ifndef __cplusplus

    #define _GNU_SOURCE

#endif

 

#include <unistd.h>

#include <dirent.h>

#include <sys/types.h> // for opendir(), readdir(), closedir()

#include <sys/stat.h> // for stat()

 

#ifdef __cplusplus

    #include <iostream>

    #include <cstdlib>

    #include <cstring>

    #include <cstdarg>

#else

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <stdarg.h>

#endif

 

 

#define PROC_DIRECTORY "/proc/"

#define CASE_SENSITIVE    1

#define CASE_INSENSITIVE  0

#define EXACT_MATCH       1

#define INEXACT_MATCH     0

 

 

int IsNumeric(const char* ccharptr_CharacterList) {

    for ( ; *ccharptr_CharacterList; ccharptr_CharacterList++)

        if (*ccharptr_CharacterList < '0' || *ccharptr_CharacterList > '9')

            return 0; // false

    return 1; // true

}

 

int strcmp_Wrapper(const char *s1, const char *s2, int intCaseSensitive) {

    if (intCaseSensitive)

        return !strcmp(s1, s2);

    else

        return !strcasecmp(s1, s2);

}

 

int strstr_Wrapper(const char* haystack, const char* needle, int intCaseSensitive) {

    if (intCaseSensitive)

        return (int) strstr(haystack, needle);

    else

        return (int) strcasestr(haystack, needle);

}

 

#ifdef __cplusplus

pid_t GetPIDbyName(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)

#else

pid_t GetPIDbyName_implements(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)

#endif

{

    char chrarry_CommandLinePath[100]  ;

    char chrarry_NameOfProcess[300]  ;

    char* chrptr_StringToCompare = NULL ;

    pid_t pid_ProcessIdentifier = (pid_t) -1 ;

    struct dirent* de_DirEntity = NULL ;

    DIR* dir_proc = NULL ;

    int (*CompareFunction) (const char*, const char*, int) ;

    if (intExactMatch)

        CompareFunction = &strcmp_Wrapper;

    else

        CompareFunction = &strstr_Wrapper;

    dir_proc = opendir(PROC_DIRECTORY) ;

    if (!dir_proc) {

        perror("Не удалось открыть " PROC_DIRECTORY " директорию") ;

        return (pid_t) -2 ;

    }

    // цикл пока не NULL

    while ( (de_DirEntity = readdir(dir_proc)) ) {

        if (de_DirEntity->d_type == DT_DIR) {

            if (IsNumeric(de_DirEntity->d_name)) {

                strcpy(chrarry_CommandLinePath, PROC_DIRECTORY) ;

                strcat(chrarry_CommandLinePath, de_DirEntity->d_name) ;

                strcat(chrarry_CommandLinePath, "/cmdline") ;

                FILE* fd_CmdLineFile = fopen (chrarry_CommandLinePath, "rt") ;  // открыть файл для чтения текста

                if (fd_CmdLineFile) {

                    fscanf(fd_CmdLineFile, "%s", chrarry_NameOfProcess) ; // прочитать из /proc/<NR>/cmdline

                    fclose(fd_CmdLineFile);  // закройте файл перед выходом из процедуры

                    if (strrchr(chrarry_NameOfProcess, '/'))

                        chrptr_StringToCompare = strrchr(chrarry_NameOfProcess, '/') +1 ;

                    else

                        chrptr_StringToCompare = chrarry_NameOfProcess ;

                    //printf("Имя процесса: %s\n", chrarry_NameOfProcess);

                    //printf("Чистое имя процесса: %s\n", chrptr_StringToCompare );

                    if ( CompareFunction(chrptr_StringToCompare, cchrptr_ProcessName, intCaseSensitiveness) ) {

                        pid_ProcessIdentifier = (pid_t) atoi(de_DirEntity->d_name) ;

                        closedir(dir_proc) ;

                        return pid_ProcessIdentifier ;

                    }

                }

            }

        }

    }

    closedir(dir_proc) ;

    return pid_ProcessIdentifier ;

}

 

#ifdef __cplusplus

    pid_t GetPIDbyName(const char* cchrptr_ProcessName) {

        return GetPIDbyName(cchrptr_ProcessName, CASE_INSENSITIVE, EXACT_MATCH) ;

    }

#else

    // C не может перегружать функции – исправлено

    pid_t GetPIDbyName_Wrapper(const char* cchrptr_ProcessName, ... ) {

        int intTempArgument ;

        int intInputArguments[2] ;

        // intInputArguments[0] = 0 ;

        // intInputArguments[1] = 0 ;

        memset(intInputArguments, 0, sizeof(intInputArguments) ) ;

        int intInputIndex ;

        va_list argptr;

        va_start( argptr, cchrptr_ProcessName );

            for (intInputIndex = 0;  (intTempArgument = va_arg( argptr, int )) != 15; ++intInputIndex) {

                intInputArguments[intInputIndex] = intTempArgument ;

            }

        va_end( argptr );

        return GetPIDbyName_implements(cchrptr_ProcessName, intInputArguments[0], intInputArguments[1]);

    }

    #define GetPIDbyName(ProcessName,...) GetPIDbyName_Wrapper(ProcessName, ##__VA_ARGS__, (int) 15)

#endif

int main() {

    pid_t pid = GetPIDbyName("bash") ; // Если -1 = не найден, если -2 = ошибка доступа к фс.

    printf("PID %d\n", pid);

    return EXIT_SUCCESS;

}

Ответ 3

PS и все остальные инструменты (ЗА ИСКЛЮЧЕНИЕМ модулей ядра) читают данные из /proc. /proc это специальная файловая система, созданная ядром «на лету», чтобы процессы пользовательского режима могли читать данные, которые иначе будут доступны только ядру. Поэтому рекомендуемым способом является чтение из /proc. Вы можете быстро интуитивно взглянуть на файловую систему /proc, чтобы понять, как она устроена. Для каждого процесса существует папка /proc/pid, где pid это идентификационный номер процесса. Внутри этой папки есть несколько файлов, которые содержат различные данные о текущем процессе. Если вы запустите:

strace ps -aux

вы увидите, как программа ps считывает эти данные из /proc.

Ответ 4

Чтение proc не так уж плохо. Я не могу показать вам код на C++, но следующий D-код должен указать вам правильное направление:

import std.stdio;

import std.string;

import std.file;

import std.regexp;

import std.c.linux.linux;

alias std.string.split explode;

string srex = "^/proc/[0-9]+$";

string trex = "State:[ \t][SR]";

RegExp rex;

RegExp rext;

   string[] scanPidDirs(string target) {

      string[] result;

      bool callback(DirEntry* de) {

         if (de.isdir) {

            if (rex.find(de.name) >= 0) {

                string[] a = explode(de.name, "/");

                string pid = a[a.length-1];

                string x = cast(string) std.file.read(de.name ~ "/status");

                int n = rext.find(x);

                if  (n >= 0) {

                    x = cast(string) std.file.read(de.name ~ "/cmdline");

                    // Это нулевое окончание

                    if (x.length) x.length = x.length-1;

                    a = explode(x, "/");

                    if (a.length)

                       x = a[a.length-1];

                    else

                       x = "";

                     if  (x == target)

                    {

                        result ~= pid ~ "/" ~x;

                    }

                }

             }

          }

          return true;

      }

      listdir("/proc", &callback);

      return result.dup;

   }

 

void main(string[] args) {

    rex= new RegExp(srex);

    rext= new RegExp(trex);

    string[] a = scanPidDirs(args[1]);

    if (!a.length) {

        writefln("Not found");

        return;

    }

    writefln("%d процессы совмещения ", a.length);

    foreach (s; a) {

       string[] p = explode(s, "/");

       int pid = atoi(p[0]);

       writef("Stop %s (%d)? ", s, pid);

       string r = readln();

       if (r == "Y\n" || r == "y\n")

          kill(pid, SIGUSR1);

    }

}

Схожие статьи

Linux

Что мешает кому-то установить некоторую запись для моего домена?

Linux

Существующие решения, позволяющие использовать контроль версий для файлов конфигурации сервера

Linux

Запуск jmap, получение которого невозможно без открытия файла сокета

Linux

Как скрыть ввод пароля в терминале