Programmatically get parent pid of another process? - linux

I tried google, but found getppid() which gets the parent pid of the current process.
I need something like getppid(some_other_pid), is there such a thing? Basically takes the pid of some process and returns the parent process' pid.

I think the simplest thing would be to open "/proc" and parse the contents.
You'll find the ppid as the 4th parameter of /proc/pid/stat
In C, libproc has a get_proc_stats function for parsing that file: see Given a child PID how can you get the parent PID for an example.

or from a unix shell you can try ps -p <child_pid> -o ppid=

I am 7 years late to the party but for anyone who may stumble upon this question, here's an alternative solution on OS X. Other answers posted here are correct and sysctl() will do the job, but you can also use proc_pidinfo to obtain a lot of useful information about a process.
#include <libproc.h>
int getppid(const pid_t pid)
{
proc_bsdinfo info;
proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, sizeof(info));
return info.pbi_ppid;
}
Obviously, additional error checking is required.

You can have a look at sysctl() system call and this link.

one more way to get it from proc entry:
cat /proc/<pid>/status | grep PPid:

We can use pstree command also.
pstree -p -s <pid of the process>
pstree -s gives tree of all the ancestors. Adding -p will give you the pid as well.
Example :Assume there is a process with pid=6206. Using the pstree command
pstree -p -s 6206
You will get the process tree.
systemd(1)───lightdm(1066)───lightdm(1191)───upstart(1360)───gnome-terminal-(5222)───bash(5229)───cpu-print(6206)
Here the parent PID is 5229

An easy way to craft this in pure C with only standard libraries:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXBUF (BUFSIZ * 2)
int pgetppid(int pid) {
int ppid;
char buf[MAXBUF];
char procname[32]; // Holds /proc/4294967296/status\0
FILE *fp;
snprintf(procname, sizeof(procname), "/proc/%u/status", pid);
fp = fopen(procname, "r");
if (fp != NULL) {
size_t ret = fread(buf, sizeof(char), MAXBUF-1, fp);
if (!ret) {
return 0;
} else {
buf[ret++] = '\0'; // Terminate it.
}
}
fclose(fp);
char *ppid_loc = strstr(buf, "\nPPid:");
if (ppid_loc) {
ppid = sscanf(ppid_loc, "\nPPid:%d", &ppid);
if (!ppid || ppid == EOF) {
return 0;
}
return ppid;
} else {
return 0;
}
}
int main () {
int ppid, pid = 373; // my current cron pid
ppid = pgetppid(pid);
printf("PPid = %d\n", ppid);
}

Related

How to invoke an executable in the path /usr/bin using a C++ program?

I have an GUI based executable in the path /usr/bin in the linux machine
This executable takes three arguments - two integer values and one char
Can you let me know how to invoke and run this executable from a user space C++ program
Not leaving this unanswered for no reason
pid_t runprocess(int arg1, int arg2, char arg3)
{
static const char program[] = "/usr/bin/...";
char arg1c[12];
char arg2c[12];
char arg3c[2];
sprintf(arg1c, "%d", arg1);
sprintf(arg2c, "%d", arg2);
arg3c[0] = arg3;
arg3c[1] = 0;
pid_t pid = vfork();
if (pid == 0) {
signal(SIGHUP, SIG_IGN); /* since it's a GUI program, detach from console HUP */
close(0); /* and detach from stdin */
if (open("/dev/null", O_RDWR)) _exit(137); /* assertion failure */
execl(program, program, arg1c, arg2c, arg3c, NULL);
_exit(errno);
}
return pid;
}
Build arguments as strings, fork and exec it. Trivial really. Don't forget to wait().
Since the child process is a GUI process, we detach HUP from the terminal we may or may not be running on and replace stdin with /dev/null.

How to execute a bash-skript from c without STDIN and STDOUT

I'm in the proccess of writing a deamon, which runs a shell-skript or any other executable upon a buzzer-press. Most of what I need works quite fine, but I'm facing a curious issue:
I do the call of the executable via execlp. And, when I do have STDIN and STDOUT open, this works just beautifully.
However, as this is supposed to be handled completely deamonized, thus in the background, I would like to run this without any console-interface. But, as soon as I close the standard interface identifiers, execlp does not work anymore.
I tried it with the snippet below: When it is run with a d as argument for debug, the identifiers will be kept open and it works. Otherwise, it does not. Thus, the question is: How to run an executable (by any means), without using STDIN and STDOUT.
Some remarks:
The call to execlp does not return. Which means, that the syslog-call is never done and which is as expected.
When leaving STDERR open, nothing comes up.
The script to be called returns with an error-code (consciously for debugging reasons).
When executing with file-handlers open, I do see the toggling of the pins and the wait-call returns the error-code of the sript.
When executing without the file-handlers, the wait call returns the exit-status success.
Note, that the c call to execlp does not return. Thus, inside this little programm, it looks like success.
Here is the c-code:
/** Global Includes: ****************************************************************/
#include <stdio.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/wait.h>
/** Main-Function: ******************************************************************/
int main (int argc, char **argv) {
/** Variables: */
pid_t pid, sid;
/** Set up the demon: ***********************************************************/
pid = fork();
if (pid < 0) {
return -2;
}
/** If we got a good PID, then we can exit the parent process: */
if (pid > 0) {
printf("Sturting Deamon as PID %i.\n", pid);
int iStatus;
pid_t pid;
pid = waitpid(-1, &iStatus, 0);
if ((pid == 0) || (pid == -1)) {
printf("Client exited unknown!\n");
}else{
if (WEXITSTATUS(iStatus) == 0) {
printf("Client %i exited success!\n", pid);
}else{
printf("Client %i exited with error!\n", pid);
}
}
return 0;
}
/** Close out the standard file descriptors: */
if ((argv[1][0]) != 'd') {
close(STDIN_FILENO);
close(STDOUT_FILENO);
//close(STDERR_FILENO);
}
/** Open syslog: */
openlog( "BuzzerD", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_LOCAL0 );
/** Try to run: */
execlp("bash", "bash", "/home/pi/TexPrint", "/home/pi/SoLieb.tex", NULL);
syslog(LOG_ERR | LOG_DAEMON, "FAILURE running execlp!");
_exit(1);
}
Here is the sript to be called:
#SOURCE=$1
#TARGET=${SOURCE/tex/pdf}
#echo Compiling $SOURCE to $TARGET and print!
#echo pdflatex $SOURCE
#echo Trying to print $TARGET ...
#echo lp -d Brother_MFC_J5930DW $TARGET
#echo .
/home/pi/BuzzerD/buzzerd -l off
sleep 3
/home/pi/BuzzerD/buzzerd -l alive
exit 1

How does execl deal with "/bin/sh" in Linux?

I read about APUE 3rd, 8.13, system Function, and I saw a version of system function implementation without signal handling.Code is like below:
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
int system(const char *cmdstring) /* version without signal handling */
{
pid_t pid;
int status;
if (cmdstring == NULL)
return(1); /* always a command processor with UNIX */
if ((pid = fork()) < 0) {
status = -1; /* probably out of processes */
} else if (pid == 0) { /* child */
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); /* execl error */
} else { /* parent */
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1; /* error other than EINTR from waitpid() */
break;
}
}
}
return(status);
}
And the code used to test system function of this version is like below:
int main(void)
{
int status;
if ((status = system("date")) < 0)
err_sys("system() error");
pr_exit(status);
if ((status = system("nosuchcommand")) < 0)
err_sys("system() error");
pr_exit(status);
if ((status = system("who; exit 44")) < 0)
err_sys("system() error");
pr_exit(status);
exit(0);
}
And the result of the test code is shown by the picture(just ignore the Chinese in the result if you can't understand):
I wonder why will execl return if "nosuchcommand", which is not valid for /bin/sh, is given to /bin/sh. In my point of view, execl just replace the code of current process and then run from entry point, even though "nosuchcommand" is not valid for /bin/sh, it has nothing to do with execl but /bin/sh. So, how execl know "nosuchcommand" is not valid for /bin/sh to execute and return? Does execl treat /bin/sh differently by checking the command given to /bin/sh before executing /bin/sh so that it will know the invalid argument given to /bin/sh in advance? I know execl won't treat /bin/sh differently, so, how does execl know "nosuchcommand" is not valid for /bin/sh to execute and return?
sh -c nosuchcommand itself returns 127. It's one of those return codes with a special meaning.
So I don't think you're seeing execl actually returning in this case.
It doesn't "know". It simply executes what you tell it to. /bin/sh then reports that it cannot find it, after which /bin/sh exits with non-zero exit code, in this case 127.
Also note that you cannot depend on it returning exactly 127 as that is shell-specific. Some shells (including /bin/sh on some OSes) will return 1 instead.

Father-child process use pipe to talk, hangs after "execlp", why?

I've got a simple text file called "tmp" under current directory, I wish to "cat" this file and then "sort" it, I want to use a c program to act like pipe "|" so I tried to use a father/child talk to do this.
Unexpectedly, the program hangs after "cat", like below:
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
int main(){
int pipefd[2];
pipe(pipefd);
int& readfd=pipefd[0];
int& writefd=pipefd[1];
pid_t pid=fork();
if(pid==0){//child
dup2(STDIN_FILENO,writefd);
close(readfd);
execlp("cat","cat","tmp",NULL);
printf("child cat ends\n");
exit(0);
}else{//father
dup2(STDOUT_FILENO,readfd);
close(writefd);
execlp("sort","sort",NULL);
printf("father sort ends\n");
}
int status;
wait(&status);
printf("father exists\n");
return 0;
}
g++ to compile and run this file, after "cat" tihis file, I don't even see "child cat ends", it just hangs.
Where's the problem, how to fix it?
Thanks
1) The order of arguments in dup2 is incorrect. Look at dup2
2) parameters (stdin/stdout) to dup2 are incorrect.
3) The exec() family of functions replace the process image with a new one. So the code after that call does not get to run (unless the exec() fails), so I removed those.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int pipefd[2];
pipe(pipefd);
int& readfd = pipefd[0];
int& writefd = pipefd[1];
pid_t pid = fork();
if(pid == 0){ //child
dup2(writefd, 1); // 1 is STDOUT_FILENO -- cat already has input -- needs output
close(readfd);
execlp("cat","cat","tmp.txt", NULL);
perror("execlp() failed in child");
}else{ //father
dup2(readfd, 0); // 0 is STDIN_FILENO -- because sort needs input!
close(writefd);
execlp("sort","sort", NULL);
perror("execlp() failed in parent");
}
return 0;
}

Unexplainable behaviour with replecating manual piping using dup2

I have two sets of code both trying to execute something like ls|grep pip
One that works and one that does not.
The working code creates 2 child process and uses one child each to execlp the one command and the other simply tries to do this by creating one child. I.e executing ls in say the child and the grep in the parent. This does not seem to work. And I can't seem to get any error either.
Can someone tell me what the problem is? And why it exists?
Not Working:
void runpipe()
{
pid_t childpid;
int fd[2];
pipe(fd);
int saved_stdout;
int saved_stdin;
saved_stdout=dup(STDOUT_FILENO);
saved_stdin=dup(STDIN_FILENO);
if((childpid=fork())==0)
{
dup2(fd[WRITE_END],STDOUT_FILENO);
close(fd[WRITE_END]);
execlp("/bin/ls","ls command","-l",NULL);
dup2(STDOUT_FILENO,fd[1]);
_exit(0);
}
else if(childpid>0)
{
dup2(saved_stdout,STDOUT_FILENO);
dup2(fd[READ_END],STDIN_FILENO);
close(fd[READ_END]);
execlp("/bin/grep","grep","pip",NULL);
wait();
_exit(0);
}
else
{
printf("ERROR!\n");
}
}
Here are the codes:
Working:
int runpipe(){
pid_t pid;
int fd[2];
pipe(fd);
int i;
pid=fork();
if (pid==0) {
printf("i'm the child used for ls \n");
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
execlp("ls", "ls", "-al", NULL);
_exit(0);
} else {
pid=fork();
if (pid==0) {
printf("i'm in the second child, which will be used to grep\n");
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
execlp("grep", "grep","pip",NULL);
}
else wait();
}
return 0;
}
The parent needs to close the write side of the pipe before exec'ing grep. For some reason, your code with the two children closes that file descriptor, but does not in the code with only one child. You are leaving several descriptors open, but the write side on the pipe is the important one. The reader (the exec'd grep) will not finish until all copies of the write side of the pipe are closed. By failing to close it, the grep is the one holding it open so grep will never terminate, but just wait for more data.

Resources