Мне нужен 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