2009-06-02 9 views
45

Necesito una API C/C++ que me permita enumerar los procesos en ejecución en un sistema Linux y enumerar los archivos que cada proceso tiene abiertos.Linux API para mostrar los procesos en ejecución?

Yo do no quiero terminar leyendo el sistema/proc/file directamente.

¿Alguien puede pensar en una forma de hacerlo?

+5

La utilidad lsof hace eso. Es de código abierto, lea el código y vea cómo funciona (debe usar/proc, sin embargo) – 0x6adb015

Respuesta

38

http://procps.sourceforge.net/

http://procps.cvs.sourceforge.net/viewvc/procps/procps/proc/readproc.c?view=markup

es la fuente de ps y otras herramientas de proceso. De hecho, usan proc (lo que indica que es probablemente la mejor manera convencional). Su fuente es bastante legible. El archivo

/procps-3.2.8/proc/readproc.c 

Puede ser útil. También una sugerencia útil como publicada por ephemient está enlazando a la API proporcionada por libproc, que debería estar disponible en su repositorio (o ya instalado, diría yo) pero necesitará la variación "-dev" para los encabezados y cualquier cosa.

buena suerte

+2

Sí, "lea la fuente Luke!" ;-) – lothar

+2

procps también puede compilar un 'libproc.a', que (por ejemplo) paquetes Debian en http://packages.debian.org/libproc-dev – ephemient

+0

@ephemient - Buena sugerencia sobre el enlace :) –

7

Si no lo hace, entonces creo que lo API que va a utilizar va a terminar de leer el sistema de archivos/proc. Estos son algunos ejemplos de programas que hacen esto:

Pero, por desgracia, que no constituye una API.

+6

Exactamente. Leer el sistema de archivos/proc * es * el mecanismo oficial del kernel de Linux para exportar información de proceso al espacio de usuario. Requerir una solución que no lo use básicamente es mostrar ignorancia sobre cómo funciona el sistema. No conducirá a un mejor software. –

3

La única manera de hacer esto sin leer/proc sería llamar a "ps aux", recorrer cada línea, leer la segunda columna (el PID) y llamar a lsof -p [PID] con ella.

... me gustaría sugerir la lectura/proc;)

+0

lol apuesto que grepping ps aux es portátil! jeje. Severo. –

+2

Realizar operaciones en procesos en la caja es intrínsecamente poco práctico, por lo que no creo que sea un problema en la práctica. Tenga en cuenta también que GNU ps tiene opciones para controlar el formato de salida, lo que le permite obtener solo los datos que desea sin tener que analizar toda la línea. –

+0

'ps' lee/proc, por lo que no cumple la * restricción injustificada * de la pregunta más que las otras respuestas. –

21

Si no quiere leer '/ proc. Luego puede considerar escribir un módulo Kernel que implementará su propia llamada al sistema. Y su llamada al sistema debe ser escrito para que pueda obtener la lista de los procesos actuales, tales como:

/* ProcessList.c 
    Robert Love Chapter 3 
    */ 
    #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"); 
    } 

El código anterior se ha tomado de mi artículo aquí en http://linuxgazette.net/133/saha.html .Una vez que tenga su propia llamada al sistema, se puede llámalo desde tu programa de espacio de usuario.

+6

Hacer que su programa dependa de un módulo kernel personalizado es mucho más sucio que leer/proc /. No haría esto sin una buena razón ... – aksommerville

+0

¿No debería haber algún bloqueo? – Beginner

+2

Escribir nuevas llamadas al sistema generalmente es una mala idea. Lo peor que puede obtener es ejecutar una lista de procesos sin él. Escribir una nueva llamada al sistema debería tener una buena razón. [Linux kernel development book] (http://www.linuxjournal.com/content/book-excerpt-linux-kernel-development-3rd-edition) lo describe brevemente. – gumik

4

PS y cualquier otra herramienta (EXCEPTO para Kernel Modules) lea desde /proc. /proc es un sistema de archivos especial creado sobre la marcha por el kernel para que los procesos en modo usuario puedan leer datos que de otro modo solo estarían disponibles para el kernel.

Por lo tanto, la manera recomendada es leer desde /proc.

Puede buscar intuitivamente el sistema de archivos /proc para ver cómo está estructurado. Para cada proceso hay un /proc/pid donde pid es el número de identificación del proceso. Dentro de esta carpeta hay varios archivos que incluyen diferentes datos sobre el proceso actual. Si ejecuta

strace ps -aux 

verá cómo el programa ps lee estos datos de /proc.

1

Reading proc no es tan malo. No puedo mostrar en C++, pero el siguiente código D, tiene que introducir en la dirección correcta:

 
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"); 
        // This is null terminated 
        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 matching processes", 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); 
    } 
} 
4

Aquí tiene (C/C++):

Usted podría haber encontrado aquí: http://ubuntuforums.org/showthread.php?t=657097

#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 ; 
} 
+1

Tipo extraño que se ve en 'strstr_Wrapper()'. 'return (strstr (haystack, needle)! = NULL)' probablemente mejor. –

+0

Esencialmente, bucle a través de todas las carpetas numéricos en/proc/, entonces readlink/proc//exe, o cat/proc//cmdline –

+0

es posible conseguir un desbordamiento de pila de 'chrarry_NameOfProcess [300] '. Este código no es tan bueno. –

3

Hay una biblioteca libprocps del procps-ng project. En Ubuntu 13.04, si haces strace ps, entonces puedes ver que ps usa libprocps.

+0

Esto parece ser el camino a seguir ahora. Una forma bastante estandarizada de leer los datos '/ proc/###/*' sin tener que averiguar cómo leer los campos disponibles. –

0

Una forma sencilla de aleta pid de cualquier proceso mediante el nombre de

pid_t GetPIDbyName(char* ps_name) 
{ 

    FILE *fp; 
    char *cmd=(char*)calloc(1,200); 
    sprintf(cmd,"pidof %s",ps_name); 
    fp=popen(cmd,"r"); 
    fread(cmd,1,200,fp); 
    fclose(fp); 
    return atoi(cmd); 
} 
Cuestiones relacionadas