Unexplainable behaviour with replecating manual piping using dup2 - linux

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.

Related

How to use fork to create a new process which will print its copy of arg?

I have to Test argv by modifying this code and I have no idea what the question is asking me... I am just learning and very new to this whole thing.
use fork to create a new process which will print its copy of argv. The
parent process should also print its own copy of argv. Run the program and direct the
output to a temp file. Open the temp file and check if both child and parent processes
print the same set of arguments. Make sure the parent waits for its child before it
terminates.
int printList(char **someList)
{
int index=0;
while(someList[index]!=NULL)
{
printf("%s\n "someList[index]);
index++;
}
return index;
}
int main (int argc, char **argv, char **envp)
>{...
}```
In Linux, forking a process spawns a new "child process" which is an exact copy of the memory and state of execution of the parent (except the return value of the fork() call itself will be different). So your question is asking you to do something like
int main (int argc, char **argv, char **envp)
{
int pid = fork();
int output_fd = file.open("temp.txt")
if(pid == 0) {//This is the child process
fprintf(output_fd, "I am the child, my args are %s", argv);
exit(0);
}
//This is the parent process, wait for child to terminate then print argv
wait(pid);
fprintf(output_fd, "I am the parent, my args are %s", argv);
}
In the output file, you should see the both the parent and child process printed their args and that they have the same argv, because memory is copied from parent to child process when you make a fork() call.

How to make system() function unblocking?

I am calling an executable from another executable in android Linux. Following is the relevant code:
...
int status = system("/system/bin/executable");
...
My requirement is not to wait for the executable to complete its execution. Means I want to run executable independent of the executable that calls it.
I have searched over the internet and didn't find how to make this system call non-blocking. Please help me to resolve it.
The system() function, without error handling, looks like this:
int system(char const *cmdline)
{
pid_t pid = fork();
if(pid == 0)
{
char const *argv[] = { "sh", "-c", cmdline, NULL };
execve("/bin/sh", argv, NULL);
_exit(1);
}
else
{
int status;
waitpid(pid, &status, 0);
return status;
}
}
The command itself is parsed by the shell, so you can use the normal & suffix to send the command into the background. The shell then terminates immediately, the background program is reparented to PID 1 (so your program isn't responsible for collecting the zombie), and system() returns.
I am able to achieve non-blocking with following code:
if (fork() == 0)
{
char *args[] = {..., NULL};
char *env[] = {..., NULL};
if (execve("/system/bin/executable", args, env) == -1)
print("Error: [%d]", errno);
}
There are few importants thing here:
fork() will create a new process. So from line if(fork() == 0), there will be 2 process running in the same space of main program.
Both processes continue executing from the point where the fork( ) calls returns execution to the main program..
fork() == 0 will let only child process in the if condition.
execve(..) will replace child process program(which is its parent program from which it copied by fork command) with /system/bin/executable.
execve(..) will not return if it get success in runing the executable else return -1.
In case of execve(..) failure the errno will be filled with the actual error.
Please correct me if I am wrong. I hope it will help someone.

daemon dies when I terminate parent process [duplicate]

This question already has answers here:
Creating a daemon in Linux
(9 answers)
Closed 5 years ago.
I expect the following code on ubuntu linux to create a daemon process which is child process of systemd and keeps printing "do something".
#include <unistd.h>
#include <stdlib.h>
int main()
{
int pid1, pid2;
int status;
if (pid1 = fork()) {
waitpid(pid1, &status, NULL);
}
else if (!pid1) {
if (pid2 = fork()) {
// use exit. return sometimes stop forking
exit(0);
}
else if (!pid2) {
while(1) {
sleep(1);
puts("do something");
}
}
else {
perror("error occured");
return -1;
}
}
else {
perror("error occured");
return -1;
}
while(1) {
sleep(1);
puts("parent do something.");
}
}
But when I interrupt the parent process, its generated daemon also terminates. The daemon only left alive when I run the code on background. Why is it like this?
Daemon alive when I run on background.
$ ./a.out &
parent do something.
do something
parent do something.
do something
(ctrl + c)
do something
do something
do something
Daemon terminates when I run not on background.
$ ./a.out
parent do something.
do something
parent do something.
do something
(ctrl + c)
// not printing anymore
$
When you run on foreground the interrupt signals generated by the terminal go to the group (parent and child). There is more info about this in the following unix exchange answer.
When running on background the process is not listening to the interrupt signals of the terminal. So pressing ctrl+c has no effect at all.

How to synchronize input and output in pipes linux?

I am creating a shell command from the custom shell to do the ssh from one terminal to another terminal.
In order to do the ssh, I am using the inbuilt ssh command of the linux. Here is my code that does the ssh login.
However, I am seeing that the I/O buffers are not in sync.
This is what I am seeing on the terminal. After SSH to the other terminal. I did the following in the terminal.
PRT# ssh 192.168.10.42
PRT# Could not create directory '/root/.ssh'.
root#192.168.10.42's password:
# screen -r
-sh: cen-: not found
# hello
-sh: el: not found
#
I don't what's the reason here. Here is the code.
int sshLogin(chr *destIp)
{
char cmd[CMD_LEN];
char readbuff[CMD_LEN];
pid_t pid;
int ret = 0;
int fd[2];
int result;
memset(cmd,'\0',sizeof(cmd));
int status = 0;
/** --tt required to force pseudowire allocation because we are behind screen app **/
sprintf(cmd,"/usr/bin/ssh -tt %s",destIp);
/** create a pipe this will be shared on fork() **/
pipe(fd);
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0 )
{
/** Child Process of Main APP --Make this parent process for the command**/
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0)
{
/** basically Main APP grand child - this is where we running the command **/
ret = execlp("ssh", "ssh", "-tt", destIp, NULL);
printf("done execlp\r\n");
}
else
{
/** child of Main APP -- keep this blocked until the Main APP grand child is done with the job **/
while( (read(fd[0], readbuff, sizeof(readbuff))))
{
printf("%s",readbuff);
}
waitpid(0,&status,0);
LOG_STRING("SSH CONNC CLOSED");
exit(0);
}
}
else
{
/** Parent process APP MAIN-- **/
/** no need to wait let APP MAIN run -- **/
}
return 0;
}
Based on Patrick Ideas.
POST 2# - It seems that it works when we close the stdin in the parent process. However, it becomes very slugguish, I feel like I am typing the keyboard too slow. The system becomes too sluggish. Also, I have a web-server from this terminal. I see that I can no longer access the web.
So, the solution is somewhere around stdin but I am not sure.
int sshLogin(chr *destIp)
{
char cmd[CMD_LEN];
char readbuff[CMD_LEN];
pid_t pid;
int ret = 0;
int fd[2];
int result;
memset(cmd,'\0',sizeof(cmd));
int status = 0;
/** --tt required to force pseudowire allocation because we are behind screen app **/
sprintf(cmd,"/usr/bin/ssh -tt %s",destIp);
/** create a pipe this will be shared on fork() **/
pipe(fd);
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0 )
{
/** Child Process of Main APP --Make this parent process for the command**/
if((pid = fork()) == -1)
{
perror("fork:");
return -1;
}
if( pid == 0)
{
/** basically Main APP grand child - this is where we running the command **/
ret = execlp("ssh", "ssh", "-tt", destIp, NULL);
printf("done execlp\r\n");
}
else
{
/** child of Main APP -- keep this blocked until the Main APP grand child is done with the job **/
while( (read(fd[0], readbuff, sizeof(readbuff))))
{
printf("%s",readbuff);
}
waitpid(0,&status,0);
LOG_STRING("SSH CONNC CLOSED");
exit(0);
}
}
else
{
/** Parent process APP MAIN-- **/
/** no need to wait let APP MAIN run -- **/
close(stdin);
}
return 0;
}
Basically, I have added - close(stdin);
You have 2 different processes trying to read from STDIN. This causes process 1 to get char 1, process 2 to get char 2, process 1 to get char 3, process 2 to get char 4, etc, alternating back and forth.
Your 2 processes are:
execlp("ssh", "ssh", "-tt", destIp, NULL);.
while( (read(fd[0], readbuff, sizeof(readbuff))))
Basically you need to ditch the read(fd[0],...).
My initial thought is that perhaps it is buffering the output: stdout is buffered, so unless you print a newline, nothing will be printed until a certain number of characters build up. This is because I/O operations are expensive. You can find more detail on this here. The result is that there is a delay because your program is waiting to print.
My suggestion: in your main function, before calling your sshLogin function, try disabling buffering with this line of code:
setbuf(stdout, NULL);
You can also call fflush(stdout); periodically to do the same thing, but the above method is more efficient. Try it and see if that solves your problem.

Programmatically get parent pid of another process?

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);
}

Resources