Linux API для отображения списка запущенных процессов?- с аргументами - PullRequest
3 голосов
/ 24 ноября 2011

Этот пост отвечает почти на мой вопрос: Linux API для отображения списка запущенных процессов?

Но чего не хватает в примере кода (C ++ / C - см. Ниже), так это аргументапроцесс.Например, программа с именем mypaint будет отображаться только как «python2.7», а не как полный исполняемый файл и аргументы «python2.7 /usr/bin/mypaint".

со страницы руководства proc: / proc/ [pid] / cmdline Содержит полную командную строку для процесса, если процесс не является зомби.В последнем случае в этом файле ничего нет: чтение этого файла вернет 0 символов.Аргументы командной строки появляются в этом файле в виде набора строк, разделенных нулевыми байтами ('\ 0') , с последующим нулевым байтом после последней строки.

Как я могуизменить этот код, чтобы перечислить также аргумент процесса?

#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 == NULL)
    {
        perror("Couldn't open the " PROC_DIRECTORY " directory") ;
        return (pid_t) -2 ;
    }

    // Loop while not 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") ;  // open the file for reading text
                if (fd_CmdLineFile)
                {
                    fscanf(fd_CmdLineFile, "%s", chrarry_NameOfProcess) ; // read from /proc/<NR>/cmdline
                    fclose(fd_CmdLineFile);  // close the file prior to exiting the routine

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

                    printf("Process name: %s\n", chrarry_NameOfProcess);
                    printf("Pure Process name: %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 cannot overload functions - fixed
    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") ; // If -1 = not found, if -2 = proc fs access error
    printf("PID %d\n", pid);
    return EXIT_SUCCESS ;
}

(chrarry_NameOfProcess = только исполняемый файл, как отображать также аргументы)?

Ответы [ 2 ]

4 голосов
/ 24 ноября 2011

Предполагая, что вы действительно не хотите анализировать каждый аргумент отдельно, а просто хотите напечатать их, как вы это делаете в настоящее время, простой способ:

(1) Замените fread на fscanf и прочитайте произвольно большое количество байтов. (Или сначала найдите длину файла и прочитайте количество, которое, если вы хотите сделать это профессионально.) Это прочитает все, включая нулевые байты, в ваш буфер.

(2) Перебрать буфер, заменяя пустые места пробелами.

(3) Поставить нулевое значение в конце прочитанных байтов, чтобы завершить строку.

(4) Затем распечатайте его.

Так что в вашей функции GetPIDbyName () что-то вроде:

const int BUFFERSIZE = 300;
int bytesread;
char chrarry_NameOfProcess[BUFFERSIZE] ;

//...........

    FILE* fd_CmdLineFile = fopen (chrarry_CommandLinePath, "rb") ; 

    if (fd_CmdLineFile)
    {
        //fscanf(fd_CmdLineFile, "%s", chrarry_NameOfProcess) ; 
        bytesread = fread(chrarry_NameOfProcess, 1, BUFFERSIZE, fd_CmdLineFile);

        for (int i = 0; i < bytesread; ++i)
            if (chrarry_NameOfProcess[i] == '\0')
                chrarry_NameOfProcess[i] = ' ';

        chrarry_NameOfProcess[bytesread] = '\0';

        fclose(fd_CmdLineFile);  

      //... the rest
     }
2 голосов
/ 24 ноября 2011

Чтобы прочитать строки, оканчивающиеся NULL, вам придется немного поработать.

Если вы позвоните, как и вы, fgets(buffer, size, fp) и попытаетесь напечатать результат, вы не получите то, что хотите. Причина в том, что когда вы используете printf(), чтобы попытаться напечатать результат, вы получите первую NULL-завершенную строку. После того, как вы распечатали это, вам нужно перейти к следующей строке, заканчивающейся на NULL, потому что NULL указывает на конец строки.

Итак, некоторый код для этого:

int len = 0;
while((len = read(fd, buffer, sizeof(buffer))) > 0) {
    /* NOTE: not sure if this condition is correct: might be -1. */
    if(len == sizeof(buffer)) { /* arguments too long for buffer, use what exists or print error message. */ } 
    int i = 0;
    while(i < len) {
        char *s = buffer + i;
        printf("Argument: %s\n", s);
        i += strlen(s) + 1; /* +1 skips over NULL at end of string. */
    }
}

Небольшое уточнение: buffer + i эквивалентно &buffer[i]. По сути, он обрабатывает буфер как символьный массив, который содержит несколько строк, оканчивающихся NULL, соединенных вместе.

Причина, по которой я здесь использую read() вместо fgets(), заключается в том, что при использовании fgets() сложнее определить, сколько байтов действительно было прочитано из файла. strlen() не помогает, единственный способ, который я знаю, это проверить местоположение символа новой строки, который предполагает, что в первую очередь существует новая строка. , , это безобразно.

РЕДАКТИРОВАТЬ: или вы могли бы использовать ftell (), я полагаю, но это еще страшнее!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...