PDA

View Full Version : Get Process ID for a running application



bob2oneil
8th September 2011, 21:58
I need to detemine if an application/daemon is executing under Fedora 64-bit Linux.


The application I need to check I do not have source for, and this is not
the condition of trying to write a singleton solution.

There have been a couple of solutions proposed at the following URLs for
this:

http://developer.qt.nokia.com/forums/viewthread/581

Of the first solution, using the sysctl method, under Fedora, there are
many undefines included KERN_PROC, KERN_PROC_ALL, and kinfo_proc. These
appear to be BSD specific, and it is not clear that the implementation
of sysctl under Fedora Linux would work if I were to cobble together the
BSD header defining these values.



struct kinfo_proc *result, *ptr;
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
size_t length, i;
result = NULL;
length = 0;

if (sysctl((int *)name,(sizeof(name)/sizeof(*name)) - 1, NULL, &length, NULL, 0) == -1)
return 0;

if ((result = (kinfo_proc *)malloc(length)) == NULL)
return 0;

if (sysctl((int *)name, (sizeof(name)/sizeof(*name)) - 1, result, &length, NULL, 0) == -1)
{
free(result);
return 0;
}

for (i = 0, ptr = result; (i < (length/sizeof(kinfo_proc)); ++i, ++ptr)
{
// ptr->kp_proc.p_pid contains the pid
// ptr->kp_proc.p_comm contains the name
pid_t iCurrentPid = ptr->kp_proc.p_pid;
if (strncmp(processName, ptr->kp_proc.p_comm, MAXCOMLEN) == 0)
{
free(sProcesses);
return iCurrentPid;
}
}

free(result);


Moving on to the next suggested option, was to use a QDirIterator to simply
iterate through the "/proc" file system looking for the executable name or
cmd line which matches my application.

The problem I am having with the 2nd approach is that "/proc" is so heavily
nested and full of content that I blow up my stack as a result of the iteration.

I have something like the following code segment:



QDirIterator it("/proc", QDirIterator::Subdirectories)
while (it.hasNext())
{
it.next();
QFileInfo child = it.fileInfo();

if (child.fileName() == ".." || child.fileName() == ".")
continue;

...
}


I am out of ideas, anyone think of some other options or solutions.

Is there a way of scoping QDirIterator so that it only goes 1 level deep?

From what I can tell from inspecting "/proc" on my machine, there are
running daemons for which I know the process id using the task manager,
but inspecting the entries in "/proc" does not show anything for either
the "cmdLine" or "exe" entries, which makes me question if this technique
will work.

norobro
8th September 2011, 22:46
You could use "pgrep" to obtain the pid if the application is running.
QProcess process;
QString pgm("pgrep");
QStringList args = QStringList() << "appName";
process.start(pgm, args);
process.waitForReadyRead();
if(!process.readAllStandardOutput().isEmpty())
// the app running

bob2oneil
8th September 2011, 23:07
Thanks, I will give it a try

bob2oneil
9th September 2011, 05:11
Works great, thanks for the advice, must simpler than the other two approaches.

bob2oneil
10th September 2011, 15:08
Have to pay it forward a bit, QtCentre has been a great resource for me.

Here is my source for the platform independant routine to get a list of PIDs for a program name. It works great as a singleton solution as
well with the knowledge that when searching for your own program name, there will be one entry which is the program itself, so two entries
indicates a duplicate running. I choose to return the list of PIDs in ASCII, but an integer collection could be used instead. The routine
returns the count of running programs found for a program name for consumers that only care about the number.

QtCentre as always rocks!



unsigned int System::getProcessIdsByProcessName(const char* processName, QStringList &listOfPids)
{
// Clear content of returned list of PIDS
listOfPids.clear();

#if defined(Q_OS_WIN)
// Get the list of process identifiers.
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;

if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
{
return 0;
}

// Calculate how many process identifiers were returned.
cProcesses = cbNeeded / sizeof(DWORD);

// Search for a matching name for each process
for (i = 0; i < cProcesses; i++)
{
if (aProcesses[i] != 0)
{
char szProcessName[MAX_PATH] = {0};

DWORD processID = aProcesses[i];

// Get a handle to the process.
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID);

// Get the process name
if (NULL != hProcess)
{
HMODULE hMod;
DWORD cbNeeded;

if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
{
GetModuleBaseNameA(hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(char));
}

// Release the handle to the process.
CloseHandle(hProcess);

if (*szProcessName != 0 && strcmp(processName, szProcessName) == 0)
{
listOfPids.append(QString::number(processID));
}
}
}
}

return listOfPids.count();

#else

// Run pgrep, which looks through the currently running processses and lists the process IDs
// which match the selection criteria to stdout.
QProcess process;
process.start("pgrep", QStringList() << processName);
process.waitForReadyRead();

QByteArray bytes = process.readAllStandardOutput();

process.terminate();
process.waitForFinished();
process.kill();

// Output is something like "2472\n2323" for multiple instances
if (bytes.isEmpty())
return 0;

// Remove trailing CR
if (bytes.endsWith("\n"))
bytes.resize(bytes.size() - 1);

listOfPids = QString(bytes).split("\n");
return listOfPids.count();

#endif
}

Talei
10th September 2011, 21:58
It's not entirely independent approach because You don't check if pgerp is present in the system.
And btw. this is potential security risk, because pgrep can be changed and will do "something else".
Btw. You could use i.e. process pidof.

Universal approach IMHO is to use (in Linux) /proc file sys. or sysctl

PS. Thanks for shearing and treat this post only as my 2 cents on this subject.