#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(){
char buf[10];
pid_t pid = fork();
if (pid < 0){
printf("error fork\n");
exit(1);
}
if (pid == 0){
fgets(buf,5,stdin);
printf("Child : %s\n",buf);
}
else{
wait(NULL);
char* r = fgets(buf,5,stdin);
if (r == NULL){
printf("Parent : eof = %i\n",feof(stdin));
}
else {
printf("Parent : %s\n",buf);
}
}
return 0;
}
My program is very simple : a process is forked; the child process reads 4 characters from stdin and when it finishes, the parent process reads 4 characters from stdin.
Normally, if I write characters in stdin (before the fork) the child process should read the first 4 characters and then the parent process should read the next 4 characters. It seems quit logical as fork() duplicates the parent process, including the file descriptors and opened files.
But, when I execute
echo 'aaaaaaaaa' | ./my_program
I get
Child : aaaa Parent : eof = 1
It seems that stdin has been emptied by the child process when it finished.
I having hard time explaining this behavior.
Can you help me ? :)
Standard input is usually (Is stdout line buffered, unbuffered or indeterminate by default?) line buffered by default. Check this answer to see what exactly this entails.
If you want your program to work as expected, explicitly set your standard input to be unbuffered (before the fork() call). This can be done like so:
setbuf(stdin, NULL);
Also see Should I set stdout and stdin to be unbuffered in C? for more implications of setting stdin to be unbuffered.
Try comment out after "else{"
//wait(NULL);
Related
After forking a child and dub2()-ing its stdin descriptor to the read-end of a pipe (its write-end is in the parent process) reading with read(0,...) (descriptor based) works fine. But reading with fgets(stdin,...) (stream based) does not work. Why?
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(){
char string[]="MY TEST STRING";
pid_t pid;
int bufSize=80;
char rBuf[bufSize];
int downlink[2], wrlen=0, rdlen=0, status;
memset(rBuf,0,bufSize);
if (pipe (downlink) == -1){
printf("Error with pipe()\n");
exit(4);
}
pid=fork();
if (pid>0){ //parent
wrlen=wrlen+write(downlink[1], string, strlen(string)+1);
//dprintf(downlink[1],"%s", string);
sleep(6);
}
else if (pid == 0){ // child
dup2(downlink[0],STDIN_FILENO);
//rdlen=read(downlink[0], rBuf, bufSize); //works
//rdlen=read(STDIN_FILENO, rBuf, bufSize); //works
//scanf("%s", rBuf);fflush(stdin); //doesn't work, reads up to first blank
//scanf(stdin,"%s", rBuf);fflush(stdin); //doesn't work, reads up to first blank
fgets(rBuf, bufSize, stdin);fflush(stdin); //doesn't work
printf("c: %s", rBuf), fflush(stdout);
//status =execl("/usr/bin/octave","octave","--no-gui",NULL);
//status =execl("/usr/bin/man","man",NULL);
//printf("c: status%d", status), fflush(stdout);
}
else{ //error
printf("Error with fork()\n");
exit(4);
}
return 0;
}
In this code the fork()ed child is supposed to read from stdin (which is dub2()ed to downlink[0](=read-end of pipe from writing parent)) and printf() to stdout the received contets.
If the reading happens with read() (descriptor based) everything works fine. When reading with fgets() or scanf() (stream based) no data is printed.
What am I missing here?
fgets() reads a line, but your parent process never sends a line of text. So you need to add a newline to your string
char string[]="MY TEST STRING\n";
read() however just reads whatever is in the pipe when it becomes available - it does not try to read all the data it can up till a newline character, which is why you get data back when using read()
Even when you do not send a newline, fgets() would return when the write end of the pipe gets closed. However the pipe you create in your parent process gets copied into the child process.
That means that when the parent process exits, its write end of the pipe is closed - but not the write end of the pipe in the child process - leading to the pipe still being open when the parent exit.
So make sure you close() the write end of the pipe in your child process, as you don't need it:
else if (pid == 0){ // child
close(downlink[1]);
dup2(downlink[0],STDIN_FILENO);
I want to execve a bash as a child process in a c program. The bash should essentially be controlled by the parent process: the parent process reads from stdin, stores the read input into a buffer and writes the content of the buffer to the bash through a pipe. The output of the bash is supposed to be passed through another pipe back to the parent process's stdout. For instance: the parent process reads "ls" and gives it to the bash through a pipe and receives the output of the bash through another pipe. I know this program doesn't make sense, because there are better ways to execute ls (or some other program) on behalf of the parent process. I'm actually just trying to understand how piping works and this is the first program that came into my mind. And i can't make this program work. That's what i have so far:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
int main() {
int pc[2];//"parent to child"-pipe
int cp[2];//"child to parent"-pipe
int status;
char buffer[256];
char eof = EOF;
if (pipe(pc) < 0 || pipe(cp) < 0) {
printf("ERROR: Pipes could not be created\n");
return -1;
}
pid_t child_pid = fork();
if (child_pid == 0) { //child has pid 0, child enters here
close(pc[1]);//close write end of pc
close(cp[0]);//close read end of cp
//redirecting file descriptors to stdin/stdout
dup2(cp[1], STDOUT_FILENO);
dup2(pc[0], STDIN_FILENO);
execve("/bin/bash",NULL,NULL);
} else {//parent enters here
close(cp[1]);//close write end of cp
close(pc[0]);//close read end of pc
//redirecting file descriptors to stdin/stdout
dup2(cp[0], STDOUT_FILENO);
while(1) {
read(STDIN_FILENO, buffer, 3);
write(pc[1], buffer, 3);
}
waitpid(child_pid, &status, 0);
}
return 0;
}
On execution: I type in ls, hit enter, nothing happens, hit enter again, output.
$ ./pipe
ls
bash: line 3: s: command not found
Why is only the character 's' delivered to the bash?
This is a quiz from my class, and it invovles concept around fork and pipe. I just have a several confusions about this code.
1) What does if((pid = fork() == 0) means? is it just checking fork using pid(process id), why does loop start with this?
2)close (p[1]); what does this part mean? closing the first integer of array P?
3)The while loop start after close, does it mean it read into p[0]'s size if it is not zero?
4.The two write lines, what does that mean, and why are they both named 1? are they happening at the same time?
#include <stdio.h>
#include <stdlib>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int p[2];
int i, pid, status;
char buffer[20];
pipe(p);
if((pid = fork() == 0) {
close (p[1]);
while (( i = read (p[0], buffer, sizeof("abcdefghi"))) != 0)
{ buffer [i] = '\0';
printf("read %d bytes: %s\n", i, buffer);
}
close(p[0]);
exit (0);
}
write(p[1], "abcdefghi', sizeof("abcdefghi"));
write(p[1], "123456789', sizeof("123456789"));
close(p[0]);
close(p[1]);
while(wait(&status)!= pid);
return(0);
}
You really should RTFM but :-
fork() creates an identical copy of the current procedure running from the same line of code. The only difference between the two copies is the return code from fork(). This will be 0 if you are in the newly created copy or the process id of the newly created copy if you are in the original executable (or -1 if something went wrong).
pipe(p) creates a pipe and returns two file handles in the array "p". the first handle is the output from the pipe opened for reading, the second handle is the input to the pipe open for writing. So close(p[1]) closes the input to the pipe ( this is in the new process which reads from the pipe, it is considered good practice to close the file descriptor you are not using!)
The while loop is checking "i" the return code from the read from the pipe file, this will return 0 when there is nothing to read.
I have program I cant modify, as is, and I need to execute it, write some data to its stdin and get the answer from its stdout in programmatic manner, automated.
What is the simpliest way to do this?
I suppose something like this pseudo-C-code
char input_data_buffer[] = "calculate 2 + 2\nsay 'hello world!'";
char output_data_buffer[MAX_BUF];
IPCStream ipcs = executeIPC("./myprogram", "rw");
ipcs.write(input_data_buffer);
ipcs.read(output_data_buffer);
...
PS: I thought of popen, but AFAIK there is only one-way pipes in linux
EDIT:
It is supposed it will be one-message-from-each-side communication. Firstly parent side send input to child process' stdin, then child provides output to its stdout and exits, meanwhile parent reads its stdout. Now about communication termination: I think when child process exits it will send EOF terminator to stdout, so parent will know exactly whether child done, on the other hand it is guaranteed that parent knows what kind of input child expects for.
Generally this program (parent) - a student's solution tester. It takes paths to two other executables from CLI, the first is student's program to test, the second is etalon correctly working program, which solves very same problem.
Input/output of students programs is strictly specified, so tester run both programs and compares its outputs for lots of random inputs, all mismatches will be reported.
Input/output max size is estimated at few hundreds kilobytes
Example: ..implement insertion sort algorithm ... first line there is sequence length ... second line there is sequence of numbers a_i where |a_i| < 2^31 - 1...
output first line must be sum of all elements, the second line must be sorted sequence.
Input:
5
1 3 4 6 2
Expected output:
16
1 2 3 4 6
Read Advanced Linux Programming -which has at least an entire chapter to answer your question- and learn more about execve(2), fork(2), waitpid(2), pipe(2), dup2(2), poll(2) ...
Notice that you'll need (at least in a single-threaded program) to multiplex (with poll) on the input and the output of the program. Otherwise you might have a deadlock: the child process could be blocked writing to your program (because the output pipe is full), and your program could be blocked reading from it (because the input pipe is empty).
BTW, if your program has some event loop it might help (and actually poll is providing the basis for a simple event loop). And Glib (from GTK) provides function to spawn processes, Qt has QProcess, libevent knows them, etc.
Given that the processing is simply a question of one message from parent to child (which must be complete before the child responds), and one message from child to parent, then it is easy enough to handle:
Create two pipes, one for communication to child, one for communication to parent.
Fork.
Child process duplicates the relevant ends of the pipes (read end of 'to-child' pipe, write end of 'to-parent' pipe) to standard input, output.
Child closes all pipe file descriptors.
Child execs test program (or prints a message to standard error reporting failure and exits).
Parent closes the irrelevant ends of the pipes.
Parent writes the message to the child and closes the pipe.
Parent reads the response from the child and closes the pipe.
Parent continues on its merry way.
This leaves the child process lying around as a zombie. If the parent is going to do this more than once, or just needs to know the exit status of the child, then after closing the read pipe, it will wait for the child to die, collecting its status.
All this is straight-forward, routine coding. I'm sure you could find examples on SO.
Since apparently there are no suitable examples on Stack Overflow, here is a simple implementation of the code outlined above. There are two source files, basic_pipe.c for the basic piping work, and myprogram.c which is supposed to respond to the prompts shown in the question. The first is almost general purpose; it should probably loop on the read operation (but that hasn't mattered on the machine I tested it on, which is running an Ubuntu 14.04 derivative). The second is very specialized.
System calls
pipe()
fork()
dup2()
execv()
waitpid()
close()
read()
write()
basic_pipe.c
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
static char msg_for_child[] = "calculate 2 + 2\nsay 'hello world!'\n";
static char cmd_for_child[] = "./myprogram";
static void err_syserr(const char *fmt, ...);
static void be_childish(int to_child[2], int fr_child[2]);
static void be_parental(int to_child[2], int fr_child[2], int pid);
int main(void)
{
int to_child[2];
int fr_child[2];
if (pipe(to_child) != 0 || pipe(fr_child) != 0)
err_syserr("Failed to open pipes\n");
assert(to_child[0] > STDERR_FILENO && to_child[1] > STDERR_FILENO &&
fr_child[0] > STDERR_FILENO && fr_child[1] > STDERR_FILENO);
int pid;
if ((pid = fork()) < 0)
err_syserr("Failed to fork\n");
if (pid == 0)
be_childish(to_child, fr_child);
else
be_parental(to_child, fr_child, pid);
printf("Process %d continues and exits\n", (int)getpid());
return 0;
}
static void be_childish(int to_child[2], int fr_child[2])
{
printf("Child PID: %d\n", (int)getpid());
fflush(0);
if (dup2(to_child[0], STDIN_FILENO) < 0 ||
dup2(fr_child[1], STDOUT_FILENO) < 0)
err_syserr("Failed to set standard I/O in child\n");
close(to_child[0]);
close(to_child[1]);
close(fr_child[0]);
close(fr_child[1]);
char *args[] = { cmd_for_child, 0 };
execv(args[0], args);
err_syserr("Failed to execute %s", args[0]);
/* NOTREACHED */
}
static void be_parental(int to_child[2], int fr_child[2], int pid)
{
printf("Parent PID: %d\n", (int)getpid());
close(to_child[0]);
close(fr_child[1]);
int o_len = sizeof(msg_for_child) - 1; // Don't send null byte
if (write(to_child[1], msg_for_child, o_len) != o_len)
err_syserr("Failed to write complete message to child\n");
close(to_child[1]);
char buffer[4096];
int nbytes;
if ((nbytes = read(fr_child[0], buffer, sizeof(buffer))) <= 0)
err_syserr("Failed to read message from child\n");
close(fr_child[0]);
printf("Read: [[%.*s]]\n", nbytes, buffer);
int corpse;
int status;
while ((corpse = waitpid(pid, &status, 0)) != pid && corpse != -1)
err_syserr("Got pid %d (status 0x%.4X) instead of pid %d\n",
corpse, status, pid);
printf("PID %d exited with status 0x%.4X\n", pid, status);
}
static void err_syserr(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
exit(EXIT_FAILURE);
}
myprogram.c
#include <stdio.h>
int main(void)
{
char buffer[4096];
char *response[] =
{
"4",
"hello world!",
};
enum { N_RESPONSES = sizeof(response)/sizeof(response[0]) };
for (int line = 0; fgets(buffer, sizeof(buffer), stdin) != 0; line++)
{
fprintf(stderr, "Read line %d: %s", line + 1, buffer);
if (line < N_RESPONSES)
{
printf("%s\n", response[line]);
fprintf(stderr, "Sent line %d: %s\n", line + 1, response[line]);
}
}
fprintf(stderr, "All done\n");
return 0;
}
Example output
Note that there is no guarantee that the child will complete before the parent starts executing the be_parental() function.
Child PID: 19538
Read line 1: calculate 2 + 2
Sent line 1: 4
Read line 2: say 'hello world!'
Sent line 2: hello world!
All done
Parent PID: 19536
Read: [[4
hello world!
]]
PID 19538 exited with status 0x0000
Process 19536 continues and exits
You can use expect to achieve this:
http://en.wikipedia.org/wiki/Expect
This is what a usual expect program would do:
# Start the program
spawn <your_program>
# Send data to the program
send "calculate 2 + 2"
# Capture the output
set results $expect_out(buffer)
Expect can be used inside C programs using expect development library, so you can translate previous commands directly into C function calls. Here you have an example:
http://kahimyang.info/kauswagan/code-blogs/1358/using-expect-script-cc-library-to-manage-linux-hosts
You can also use it from perl and python which usually are usually easier to program for these type of purposes than C.
I'm trying to do a simple fork -> execute another program -> say "hello" to that child process -> read back something -> print what received.
The program used as child just waits for any line of input and prints something to the stdout like "hello there!"
This is my "host" program (that is not working):
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#define IN 0
#define OUT 1
#define CHILD 0
main ()
{
pid_t pid;
int pipefd[2];
FILE* output;
char buf[256];
pipe(pipefd);
pid = fork();
if (pid == CHILD)
{
printf("child\n");
dup2(pipefd[IN], IN);
dup2(pipefd[OUT], OUT);
execl("./test", "test", (char*) NULL);
}
else
{
sleep(1);
printf("parent\n");
write(pipefd[IN], "hello!", 10); // write message to the process
read(pipefd[OUT], buf, sizeof(buf));
printf("received: %s\n", buf);
}
}
I get this:
child
[.. waits 1 second ..]
parent
received:
What am I missing? Thanks!
EDIT (test.c):
By request, this is the child program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int getln(char line[])
{
int nch = 0;
int c;
while((c = getchar()) != EOF)
{
if(c == '\n') break;
line[nch] = c;
nch++;
}
if(c == EOF && nch == 0) return EOF;
return nch;
}
main()
{
char line[20];
getln(line);
printf("hello there!", line);
fflush(stdout);
return 0;
}
You're always suppose to read from file-descriptor 0, and write to file-descriptor 1 with pipes ... you have this relationship reversed in the parent process. For what you're wanting to-do, you may end up needing two pipes for two-way communication between the parent and child that avoids situations where the parent ends up reading the contents it wrote to the pipe since process scheduling is non-deterministic (i.e., the child is not guaranteed to read what the parent wrote to the pipe if the parent is also reading from the same pipe since the parent could just end up writing and then reading with no interleaving of the child process to read what the parent wrote).
Change your code to the following:
main ()
{
pid_t pid;
int pipe_to_child[2];
int pipe_from_child[2];
FILE* output;
char buf[256];
pipe(pipe_to_child);
pipe(pipe_from_child);
pid = fork();
if (pid == CHILD)
{
printf("child\n");
//child process not using these ends of the pipe, so close them
close(pipe_to_child[1]);
close(pipe_from_child[0]);
dup2(pipe_to_child[0], fileno(stdin));
dup2(pipe_from_child[1], fileno(stdout));
execl("./test", "test", (char*) NULL);
}
else
{
sleep(1);
printf("parent\n");
write(pipe_to_child[1], "hello!\n", 10); // write message to the process
read(pipe_from_child[0], buf, sizeof(buf));
printf("received: %s\n", buf);
}
}
You need two pipes for this: one for the child process's stdin, and one for its stdout. You cannot reuse the two ends of a pipe as two pipes.
Also, this line of the parent program
write(pipefd[IN], "hello!", 10); // write message to the process
does not write a newline, so getln in the child will never return. (Furthermore, "hello!" has only six characters, but you are writing ten.)
You probably should use wait or waitpid.
It looks like you have your pipe descriptors mixed up. After calling pipe(), pipefd[0] is the read end of the pipe, and pipefd[1] is the write end of the pipe. You're writing to the read end, and reading from the write end.
Also, you're trying to use one pipe for both stdin and stdout of the child process. I don't think this is really what you want to do (you will need two pipes).
Looks like you have your IN/OUT backwards for the pipe -- pipefd[0] is the read end of the pipe, so writing to it (as the parent does) is nonsensical and will fail. Similarly pipefd[1] is the write end so reading from it (as the parent does) will also fail. You should ALWAYS check the return values of the read and write calls, to see if you're getting any errors
Others are saying that the pipe is mono-directional, which is what I thought at first. But actually that's not what my man page says:
A read from fildes[0] accesses the data written to fildes[1]
on a first-in-first-out (FIFO) basis and a read from
fildes[1] accesses the data written to fildes[0] also on a
FIFO basis.
However, this does mean that if the parent is writing to pipefd[0], then the child should read from pipefd[1], so you are associating the wrong side of the pipe with the child's stdin and stdout.
From the man page, it does seem like you can do this with one pipe. But it might be clearer code to use two.
It seems like you are thinking of each element of pipefd as a separate pipe, but that's not the case.