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

Как сделать переадресацию портов с одного IP на другой в одной и той же сети?

Linux

Как написать обработчик сигнала для перехвата SIGSEGV

Linux

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

Linux

Как используется брандмауэр?