Мне нужен C/С++ API, который позволяет мне перечислять запущенные процессы в системе Linux и перечислять файлы, открытые каждым процессом.
Я не хочу напрямую читать/proc/файловую систему.
Может ли кто-нибудь подумать о способе сделать это?
Мне нужен C/С++ API, который позволяет мне перечислять запущенные процессы в системе Linux и перечислять файлы, открытые каждым процессом.
Я не хочу напрямую читать/proc/файловую систему.
Может ли кто-нибудь подумать о способе сделать это?
http://procps.sourceforge.net/
http://procps.cvs.sourceforge.net/viewvc/procps/procps/proc/readproc.c?view=markup
Является источником ps и другими инструментами процесса. Они действительно используют proc (указывая, что это, вероятно, обычный и лучший способ). Их источник вполне читабельен. Файл
/procps-3.2.8/proc/readproc.c
Может быть полезно. Также полезное предложение как , отправленное ephemient, ссылается на API, предоставляемый libproc, который должен быть доступен в вашем репо (или уже установленном, я бы сказал), но вам понадобится вариант -dev для заголовков и что-нет.
Удача
Если вы не хотите читать из '/proc. Затем вы можете рассмотреть возможность создания модуля Kernel, который будет реализовывать ваш собственный системный вызов. И ваш системный вызов должен быть написан так, чтобы он мог получить список текущих процессов, например:
/* 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");
}
Приведенный выше код взят из моей статьи здесь, в http://linuxgazette.net/133/saha.html. Когда у вас есть свой системный вызов, вы можете позвонить ему из своего программа пользовательского пространства.
Если вы этого не сделаете, я думаю, что любой API, который вы будете использовать, закончит чтение файловой системы /proc. Вот несколько примеров выполнения этой программы:
Но, к сожалению, это не API.
Вот, пожалуйста (C/C++):
Вы могли бы найти это здесь: http://ubuntuforums.org/showthread.php?t=657097
По сути, он выполняет цикл по всем числовым папкам в /proc/<pid>
, а затем выполняет ссылку для чтения в /proc/<pid>/exe
или, если вам нужны аргументы командной строки cat /proc/<pid>/cmdline
Файловые дескрипторы, открытые процессом, находятся в /proc/<pid>/fd/<descriptor>
, и вы получаете имя файла, делая ссылку на чтение для каждой символической ссылки, например, readlink /proc/<pid>/fd/<descriptor>
. fd может быть устройством, таким как /dev/null, сокетом или файлом, и, возможно, другим.
#include
ссылка для чтения ssize_t (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 == 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 ;
}
PS и любой другой инструмент (EXCEPT для модулей ядра), начиная с /proc
. /proc
- это специальная файловая система, созданная на ходу ядром, так что процессы пользовательского режима могут читать данные, которые в противном случае будут доступны только для ядра.
Поэтому рекомендуемый способ - чтение из /proc
.
Вы можете быстро интуитивно взглянуть на файловую систему /proc
, чтобы увидеть, как ее структурировано.
Для каждого процесса существует /proc/pid
, где pid - номер идентификатора процесса. Внутри этой папки есть несколько файлов, которые содержат разные данные о текущем процессе.
Если вы запустите
strace ps -aux
вы увидите, как программа ps
считывает эти данные из /proc
.
Единственный способ сделать это без чтения /proc - это вызвать "ps aux", пройти через каждую строку, прочитать второй столбец (PID) и вызвать с ним lsof -p [PID].
... Я бы предложил чтение/proc;)
Там находится библиотека libprocps
из проекта procps-ng
. В Ubuntu 13.04, если вы выполняете strace ps
, вы можете видеть, что ps
использует libprocps
.
Чтение proc не так уж плохо. Я не могу показать вам на С++, но следующий код 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"); // 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); } }
Легкий способ запланировать pid любого процесса по имени
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);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *mystrstr(const char *haystack,const char *needle);
main()
{
char *str1="abc dc abcd abce";
char *str2="ab";
char *ptr=NULL;
int cnt=0;
int offset=0;
while(*str1)
{
ptr=mystrstr(str1,str2);
if(ptr==NULL)
break;
cnt++;
offset=ptr-str1+strlen(str2);
str1=str1+offset;
}
printf("Num of substr [%s] = %d\n",str2,cnt );
}
char *mystrstr(const char *haystack,const char *needle)
{
int i=0,j=1;
for(;haystack[i];i++)
{
if(needle[0]==haystack[i])
{
for(;needle[j];j++)
{
if(needle[j]==haystack[i+j] )
{
if(needle[j]!='\0')
continue;
}
else
break;
}
if(needle[j]=='\0')
return haystack + i;
else if(haystack[i]!='\0')
continue;
}
if(haystack[i]=='\0')
return NULL;
}
}