I need a C/C++ API that allows me to list the running processes on a Linux system, and list the files each process has open.
I do not want to end up reading the /proc/ file system directly.
Can anyone think of a way to do this?
I need a C/C++ API that allows me to list the running processes on a Linux system, and list the files each process has open.
I do not want to end up reading the /proc/ file system directly.
Can anyone think of a way to do this?
http://procps.sourceforge.net/
Is the source of ps and other process tools. They do indeed use proc (indicating it is probably the conventional and best way). Their source is quite readable. The file
/procps-3.2.8/proc/readproc.c
May be useful. Also a useful suggestion as posted by ephemient is linking to the API provided by libproc, which sould be available in your repo (or already installed I would say) but you will need the "-dev" variation for the headers and what-not.
Good Luck
If you don't do it, then I guess whatever API you will use will end upreading the /proc filesystem. Here are some examples of program doing this :
But unfortunately, that does not constitute an API.
The only way to do this without reading /proc would be to call "ps aux", go through every line, read the second column (the PID) and call lsof -p [PID] with it.
...I'd suggest reading /proc ;)
If you do not want to read from '/proc. Then you can consider writing a Kernel module which will implement your own system call. And your system call should be written so that it can obtain the list of current processes, such as:
/* 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");
}
The code above is taken from my article here at http://linuxgazette.net/133/saha.html.Once you have your own system call, you can call it from your user space program.
PS and every other tool(EXCEPT for Kernel Modules) read from /proc. /proc is a special filesystem created on the fly by the kernel so that user mode processes can read data that will otherwise will only be available for the kernel. The recommended way is therefore, reading from /proc. You can quickly intuitevelly look at the /proc filesystem to see how its structured. For every process there is a /proc/pid where pid is the process id number. Inside this folder there are several files which include different data about the current process. If you ran strace ps -aux you will see how the program ps, reads this data from /proc.
Here you go (C/C++):
You could have found it here: 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 ;
}