Given a pid, I want to find the owner of the process (as uid). Is there a way to get this in osx (or any unix) using C++?
Google didn't help. 'ps' is able to do it; so I assume there should be a way to get it programatically.
Given a pid, I want to find the owner of the process (as uid). Is there a way to get this in osx (or any unix) using C++?
Google didn't help. 'ps' is able to do it; so I assume there should be a way to get it programatically.
Solution from Indhu helped me on my way, so I would like to post my own.
UID from PID with pure C:
#include <sys/sysctl.h>
uid_t uidFromPid(pid_t pid)
{
uid_t uid = -1;
struct kinfo_proc process;
size_t procBufferSize = sizeof(process);
// Compose search path for sysctl. Here you can specify PID directly.
const u_int pathLenth = 4;
int path[pathLenth] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
int sysctlResult = sysctl(path, pathLenth, &process, &procBufferSize, NULL, 0);
// If sysctl did not fail and process with PID available - take UID.
if ((sysctlResult == 0) && (procBufferSize != 0))
{
uid = process.kp_eproc.e_ucred.cr_uid;
}
return uid;
}
No excess allocation, no loops.
The source for the ps command, reveals that there is a function called get_proc_stats
defined in proc/readproc.h that (among other things) returns the real user name(UID)
& Effective user name(EUID)
for a given pid.
You need to do install libproc-dev
to get this function. and then you can do:
#include <proc/readproc.h>
void printppid(pid_t pid)
{
proc_t process_info;
get_proc_stats(pid, &process_info);
printf("Real user of the process[%d] is [%s]\n", pid, process_info.ruser);
}
compile it with gcc the-file.c -lproc
.
Once you have the real user name you can use getpwnam() and getgrnam() functions to get the uid.
You could look at how ps does it. It looks like it uses the kvm_getprocs function.
However, it's much more portable (you said "any unix", but e.g. the Linux and Solaris way is to look in the /proc
filesystem - and other unixes may have different APIs) to just parse the output of ps (ps -o user= -p (pid)
for example, to eliminate any extraneous output) than to do any system-specific process stuff
There's not a portable way to do this. On Mac OS, you've got to use poorly documented sysctl
interfaces: see this previous stackoverflow question. (As other commenters pointed out, on Linux you can use proc. On FreeBSD, you should be able to use kvm_getfiles
, although this is not available on Mac OS.)
Your best bet is to use the source for Apple's ps
as a jumping-off point for grabbing process data and then you'll be able to use getpwuid(3)
once you have the uid.
Finally found a way to programatically do this without parsing the output of 'ps'
uint getUidUsingSysctl(uint pid)
{
struct kinfo_proc *sProcesses = NULL, *sNewProcesses;
int aiNames[4];
size_t iNamesLength;
int i, iRetCode, iNumProcs;
size_t iSize;
iSize = 0;
aiNames[0] = CTL_KERN;
aiNames[1] = KERN_PROC;
aiNames[2] = KERN_PROC_ALL;
aiNames[3] = 0;
iNamesLength = 3;
iRetCode = sysctl(aiNames, iNamesLength, NULL, &iSize, NULL, 0);
/* allocate memory and populate info in the processes structure */
do
{
iSize += iSize / 10;
sNewProcesses = (kinfo_proc *)realloc(sProcesses, iSize);
if (sNewProcesses == 0)
{
if (sProcesses)
free(sProcesses);
/* could not realloc memory, just return */
return -1;
}
sProcesses = sNewProcesses;
iRetCode = sysctl(aiNames, iNamesLength, sProcesses, &iSize, NULL, 0);
} while (iRetCode == -1 && errno == ENOMEM);
iNumProcs = iSize / sizeof(struct kinfo_proc);
for (i = 0; i < iNumProcs; i++)
{
if (sProcesses[i].kp_proc.p_pid == pid)
{
return sProcesses[i].kp_eproc.e_ucred.cr_uid;
}
}
/* clean up and return to the caller */
free(sProcesses);
return -1;
}
Note: There might be a better way to get 'kinfo_proc' instead of iterating through all process.