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

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

Related

Child process cannot get the input from stdin written by parent process

In child process, I use execl() to execute a program "test1" with the input from stdin. However, the input from stdin cannot be passed to "test1", but it is fine for "sort" command.
example.c
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int fds[2]; // an array that will hold two file descriptors
pipe(fds); // populates fds with two file descriptors
pid_t pid = fork(); // create child process that is a clone of the parent
if (pid == 0) { // if pid == 0, then this is the child process
dup2(fds[0], STDIN_FILENO); // fds[0] (the read end of pipe) donates its data to file descriptor 0
close(fds[0]); // file descriptor no longer needed in child since stdin is a copy
close(fds[1]); // file descriptor unused in child
//if (execl("/usr/bin/sort", "sort", (char *)0) < 0) exit(0);//working
if (execl("./test1", "test1", (char *)0) < 0) exit(0);//not working
}
// if we reach here, we are in parent process
close(fds[0]); // file descriptor unused in parent
const char *words[] = {"pear", "peach", "apple"};
// write input to the writable file descriptor so it can be read in from child:
size_t numwords = sizeof(words)/sizeof(words[0]);
for (size_t i = 0; i < numwords; i++) {
dprintf(fds[1], "%s\n", words[i]);
}
// send EOF so child can continue (child blocks until all input has been processed):
close(fds[1]);
int status;
pid_t wpid = waitpid(pid, &status, 0); // wait for child to finish before exiting
return wpid == pid && WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}
For "sort" command, the output is:
$ ./example
apple
peach
pear
For "test1" , the output is:
$ ./example
hello!
test1
If it is working for "test1", the output should be:
$ ./test1 pear peach apple
hello!
./test1
pear
peach
apple
test1.c
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char** argv){
printf("hello!\n");
for(int i = 0; i < argc; i++){
printf("%s\n", argv[i]);
}
return 0;
}
What am I doing wrong?
test1 doesn't read any input, so passing it input doesn't work.
To get your sample output have test1 execl cat.

Linux Pipes and Redirecting output

I'm trying to write a linux program using pipes, but so far I've encountered a major problem.
When I try to run this, it seems it either duplicates the answers, or doesnt give me an answer at all.
So far I'm trying to use a pipe, the parent gets a string from the keyboard, and compares it to see if matches any other commands, momentarily its only the "login" command.
But it doesnt work as it doesnt show me a fail or success message. I've been fiddeling with the code, but sometimes it's repeating the answer several time, like it's executing the child several times. Can someone explain me why its happening?
Thx
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
int fd[2], nbytes;
pid_t childpid;
char input[12];
char readbuffer[80];
int log_variable;
int pid;
int compare(char str1[], char str2[]){
if(strlen(str1) == strlen(str2))
{int i;
for( i=0; i<strlen(str1); i++){
if(str1[i] != str2[i])
return 0;
return 1;
}
}
}
int test(char argument[]){//test function
pipe(fd);
switch(childpid=fork()){
case -1:
perror("fork -1\n");
exit(1);
case 0://child
close (fd[1]);
int nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
if(compare(readbuffer, "login") == 1){
return 1;
}
else if(compare(readbuffer, "login") == 0){
return 0;
}
exit(1);
default:
//parent
close(fd[0]);
write(fd[1], argument, sizeof(argument));
while(wait(NULL)!=-1);
}
}
main(){
while(1){
printf("Insert command: \n");
scanf("%s", input);
logs=(test(input));
if(logs == 1) {printf("success\n"); break;}
else if(logs == 0) {printf("fail\n"); continue;}
}
return 0;
}
a couple of problems for your code with a quick look:
compare function doesn't return value if length not equal.
test() function may get called twice in one process, which means fork more times.
the test() internally for the child will return to the main, also parent will return to main ... get things more complicated here (the child may fork a third time ...)
Use "strace -F" can give you a much better view what things happened behind.

Why the program didn't execute some sentences in this C programming or unix programming(execvp() System calls)?

I have the following program, when I run the program, I feel really confused that why my program didn't excute
int num=i;
printf("it is No.%d !",num);
printf("hello , I will excute execvp!");
My program basically create 6 child processes to excute executionbode() function, and then use execvp to overload original program. However, everytime when I run the program, the string "hello, I will execute execvp" never shows up! Also I think those three sentences above also didn't execute in the running program? can someone tell me why? Here is my program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include "makeargv.h"
#include "redirection.h"
#include <sys/wait.h>
int executionnode(int i);
int main(){
pid_t childpid;
int i;
int row=6;
for(i=0;i<row;i++)
{ childpid=fork();
if(childpid==0)
continue;
else if (childpid>0)
executionnode(i);
else {
perror("something wrong");
exit(1);
}
}
}
int executionnode(int i){
sleep(i);
printf("hello, I am process:%ld\n",(long)getpid());
wait(NULL);
char *execArgs[] = { "echo", "Hello, World!", NULL };
int num=i;
printf("it is No.%d !",num);
printf("hello , I will excute execvp!");
execvp("echo", execArgs);
}
Can someone tell me why? and how to fix it? I feel it is really strange? Is it because of execvp() functions? I just began to learn operating system,so I am really confused about it! Thank you for helping me!
As user3629249 said you have some confusion. You'll get many children of children of children... and that wait(NULL) is useless :).
I used this structure to got your goal in my OS subject excercises.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#define N 5
int main(int argc, char const *argv[])
{
pid_t pid,pids[N];
int i, num_pids = 0;
int state = 0;
int prior[]={1,3,5,2,4};
pid_t parent_pid = getpid();
printf("Parent pid is %i\n",father_pid);
// This for loop is the key
for (i = 0; i < N && getppid() != parent_pid; i++)
{
if ((pid = fork()) < 0)
{
printf ("fork error\n");
exit(-1);
}
pids[num_pids++] = pid;
}
if (pid == 0) // Child processes
{
printf("I am the child %i\n",getpid());
}
else // Parent process
{
for (i = 0; i < N; i++)
{
int pid_index = prior[i]-1; // Array starts with 0
pid = waitpid(pids[pid_index]);
printf("Children %i ended\n",pids[indice_pid]);
printf("%i alive children\n",N-1-i);
}
}
return 0;
}
This structure works because you save the parent's pid in parent_pid variable and compare the parent of each process pid with getppid(). If this pid is different that parent_pid, this proccess is the parent. In another case the process is a child so it has to stop (these processes don't have to fork). With this way you can get only the forks you need.
The rest of the code is the same: Pid==0 is child process and any other is the parent. You can call executionnode(int i) in child processes block (remember, pid==0 !!! you have a mistake). i variable should have the right value in each call I think.
Good luck!

Fail to wake up from epoll_wait when other process closes fifo

I'm seeing different epoll and select behavior in two different binaries and was hoping for some debugging help. In the following, epoll_wait and select will be used interchangeably.
I have two processes, one writer and one reader, that communicate over a fifo. The reader performs an epoll_wait to be notified of writes. I would also like to know when the writer closes the fifo, and it appears that epoll_wait should notify me of this as well. The following toy program, which behaves as expected, illustrates what I'm trying to accomplish:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <unistd.h>
int
main(int argc, char** argv)
{
const char* filename = "tempfile";
char buf[1024];
memset(buf, 0, sizeof(buf));
struct stat statbuf;
if (!stat(filename, &statbuf))
unlink(filename);
mkfifo(filename, S_IRUSR | S_IWUSR);
pid_t pid = fork();
if (!pid) {
int fd = open(filename, O_WRONLY);
printf("Opened %d for writing\n", fd);
sleep(3);
close(fd);
} else {
int fd = open(filename, O_RDONLY);
printf("Opened %d for reading\n", fd);
static const int MAX_LENGTH = 1;
struct epoll_event init;
struct epoll_event evs[MAX_LENGTH];
int efd = epoll_create(MAX_LENGTH);
int i;
for (i = 0; i < MAX_LENGTH; ++i) {
init.data.u64 = 0;
init.data.fd = fd;
init.events |= EPOLLIN | EPOLLPRI | EPOLLHUP;
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &init);
}
while (1) {
int nfds = epoll_wait(efd, evs, MAX_LENGTH, -1);
printf("%d fds ready\n", nfds);
int nread = read(fd, buf, sizeof(buf));
if (nread < 0) {
perror("read");
exit(1);
} else if (!nread) {
printf("Child %d closed the pipe\n", pid);
break;
}
printf("Reading: %s\n", buf);
}
}
return 0;
}
However, when I do this with another reader (whose code I'm not privileged to post, but which makes the exact same calls--the toy program is modeled on it), the process does not wake when the writer closes the fifo. The toy reader also gives the desired semantics with select. The real reader configured to use select also fails.
What might account for the different behavior of the two? For any provided hypotheses, how can I verify them? I'm running Linux 2.6.38.8.
strace is a great tool to confirm that the system calls are invoked correctly (i.e. parameters are passed correctly and they don't return any unexpected errors).
In addition to that I would recommend using lsof to check that no other process has that FIFO still opened.

OS-X Linux intercept process call

how do I intercept calls made from other process which I have called from my process. (say - I call make and I would like to intercept and modify call to gcc from make).
Here is a small example with ptrace:
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/user.h>
#include <sys/prctl.h>
const char *sys_call_name(long num);
int main()
{
pid_t pid = fork();
struct user_regs_struct regs;
if (!pid) {
/* child */
while (1) { printf("C\n"); sleep(1); }
}
else { /* parent */
int status = 0;
ptrace(PTRACE_ATTACH, pid, NULL, 0);
ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_SYSCALL) ;
while (1) {
printf("waiting\n");
pid = wait(&status);
/* child gone */
//if (WIFEXITED(status)) { break; }
ptrace(PTRACE_GETREGS, pid, 0, &regs);
/* regs.orig_eax is the system call number */
printf("A system call: %d : %s\n", regs.orig_eax, sys_call_name(regs.orig_eax));
/* let child continue */
ptrace(PTRACE_SYSCALL, pid, NULL, 0);
}
}
return 0;
}
const char *sys_call_name(long num) {
switch(num) {
case 4: return "write";
case 162: return "nanosleep";
case 165: return "getresuid";
case 174: return "rt_sigaction";
case 175: return "rt_sigprocmask";
default: return "unknown";
}
}
It sound from your question that you are looking for Makefile help, specifically you are looking for doing something for all call to the c-compiler.
make allows for any command to be redefined locally -- all you have to do is redefine the macro in make -- for gcc you would simply redefine the CC macros.
You could do that from the command like, like
make CC=echo
which would substitute all call from gcc to echo (not very useful, but you get the idea).
Or you can do it in the Makefile by adding a line like
CC=echo
testprogram: testprogram.o
and when you do make testprogram the make will echo something rather than invoking gcc
You don't easily. The facility in question is the ptrace function, not for the faint of heart.

Resources