I found this Redirect ouput to another instance terminal window post and tried to play with similar code alternatives, but got unexpected results when using the sleep function, or similar, in conjunction with the fork function.
I run the code below from a ("parent") terminal window. The program is supposed to open another (child) terminal window and print some text to both the parent and child terminals in an infinite loop.
The issue is that the frequency of the printing in each window is not the same, in fact it can be very different.
I tried 4 alternative loops (one need to comment out only 1 of the 4 alternatives at the same time). The alternative-1 is too fast to see much and the printing frequencies look similar in both windows.
The issues arise when I try to slow down the loop, either with the sleep function or a long secondary loop (*), in the alternatives-2, -3 and -4. There, one can see that the timing of text outputs becomes out of sync between the 2 terminals and, while the messages (seem to) print with the desired periodicity in the parent window, e.g. with 1 second delay with sleep(1), the periodicity in the child window seems random and lagging (eg on my machine it takes ~200 seconds before the first output in the child window). Alternative-4 is similar to alternative-2, but with fwrite instead of fprintf.
My questions : why such a lag between the two windows? Is this lag "deterministic" or random? What would be the way to make both terminals print at the same, regular, frequency?
I'm on Linux. gcc logwindow.c -o logwindow should be enough to compile the code.
(*) I am aware that using a long loop (in alternative-3) instead of the sleep function is bad practice. I just tried to see if it would give different results from the sleep function.
#include <stdlib.h> // system
#include <stdio.h> // tempnam, sprintf
#include <unistd.h> // sleep
#include <sys/types.h> // pid_t
FILE *logwindow(){
char *fp = tmpnam(NULL); //generate a random filepath/name
char cmd[256];
pid_t pid;
mkfifo(fp, 0777);
pid = fork();
if (pid==0) {
sprintf(cmd, "xterm -e \"cat %s\"", fp);
system(cmd);
return(NULL);
}
return fopen(fp, "w");
}
int main(){
FILE *log = logwindow();
if (log == NULL) {
printf("child process, exiting\n");
exit(0);
}
else {
printf("parent process, keep going\n");
int i=0;
/* comment out only 1 alternative out of the 4 */
// alternative-1
for(;;){
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
i++;
}
// alternative-2
/*
for(;;){
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
sleep(1);
i++;
}
*/
// alternative-3
/*
int j=0;
for(i=0;i<100000;i++){
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
for(j=0;j<5000000;j++){} // simulate the sleep function
}
*/
// alternative-4
/*
char alt4text[] = "Child Terminal here\n";
for(;;){
fwrite(alt4text, 1, sizeof(alt4text),log); // print to child terminal
printf("i=%d, Parent Terminal here\n", i); // print to parent terminal
sleep(1);
i++;
}
*/
}
}
You are probably having issues with buffering.
Try calling fflush() after a call to fprintf()
fprintf(log, "i=%d, Child Terminal here\n", i); // print to child terminal
fflush(log)
Alternatively you could look into line buffering or disabling buffering entirely by using setbuf() / setvbuf()
Note also that for(j=0;j<5000000;j++){} is not a good idea - ever. This is referred to as a "busy loop", and will hog processor time - increasing power usage, temperatures, and starving other processes of resources.
This is a bad idea even if you are working on a microcontroller and should be avoided wherever possible.
Additionally, depending on compiler optimisation settings, this may produce no instructions at all, silently making alternative-3 equivalent to alternative-1.
Related
Blow is an implementation of Sieve of Eratosthenes in C
#include "kernel/stat.h"
#include "kernel/types.h"
#include "user/user.h"
void cull(int p) {
int n;
while (read(0, &n, sizeof(n))) {
// n is not prime
if (n % p != 0) {
write(1, &n, sizeof(n));
}
}
}
void redirect(int k, int pd[]) {
close(k);
dup(pd[k]);
close(pd[0]);
close(pd[1]);
}
void right() {
int pd[2], p;
// read p
if (read(0, &p, sizeof(p))) {
printf("prime %d\n", p);
pipe(pd);
if (fork()) {
// parent
redirect(0, pd);
right();
} else {
redirect(1, pd);
cull(p);
}
}
}
int main(int argc, char *argv[]) {
int pd[2];
pipe(pd);
if (fork()) {
redirect(0, pd);
right();
} else {
redirect(1, pd);
for (int i = 2; i < 36; i++) {
write(1, &i, sizeof(i));
}
}
exit(0);
I am not quite following the logic here:
1). Why does redirect need to close pd1?
2). cull() is reading from the file descriptor 0, but in right() the child process will close 0. Why doesn't this cause any problem?
3). why it is necessary to use redirect here when we only want read from 0 and write to 1?
Update:
1). I found this implementation in the following blog post:
https://abcdlsj.github.io/post/mit-6.828-lab1xv6-and-unix-utilities/
2). I think the idea is borrowed from the inventor of this algorithm
3). I think the reason that the header is so is because it is implemented in a toy operating system for educational purpose.
The code is an adaptation of the paper Coroutine prime number sieve by M. Douglas McIlroy to the Xv6 operating system, a re-implementation of Version 6 Unix used for teaching. The technique is from 1968 as an experiment in co-routines via pipes. The paper explains the algorithm and rationale.
The program implements the sieve of Eratosthenes as a kind of production line, in which each worker culls multiples of one prime from a passing stream of integers, and new workers are recruited as primes are discovered.
When Unix came to be, my fascination with coroutines led me to badger its author, KenThompson, to allow writes in one process to go not only to devices but also to matching reads in another process.
...the coroutine sieve has been a standard demo for languages or systems that support interprocess communication. Implementations using Unix processes typically place the three coroutines—source, cull and sink—in distinct executable files.The fact that the whole program can be written as a single source file, in a language that supports neither concurrency nor IPC, is a tribute not only to Unix’s pipes, but also to its clean separation of program initiation into fork for duplicating address spaces and exec for initializing them.
I believe using stdin and stdout is an artifact of its origins in the early days of Unix when piping stdin and stdout between processes was first introduced. It makes a lot more sense in shell.
#!/bin/bash
source() {
seq 2 1000000
}
cull() {
while true
do
read n
(($n % $1 != 0)) && echo $n
done
}
sink() {
read p
echo $p
cull $p | sink &
}
source | sink
In C, as we'll see, it's simpler to skip the redirection and pass around pipes.
First, what's going on?
redirect is redirecting stdin and stdout to a pipe. 0 is stdin and 1 is stdout. This can be made more clear by using STDIN_FILENO and STDOUT_FILENO.
main makes a pipe.
main forks.
The child redirects stdout to the pipe.
The child streams numbers to the pipe via stdout.
The first number must be 2.
main redirects stdin to the pipe.
main calls right.
right reads the first prime, 2, from stdin which is a pipe to the number stream.
[number stream] ->(2) [right]
After the initial condition, a switcheroo happens inside right.
right makes a pipe.
right forks.
The child redirects its stdout to the pipe.
The child's stdin is still reading from the number stream.
The child calls cull.
cull reads from stdin (the number stream) and writes to stdout (right).
right redirects its stdin to the pipe, reading from cull.
right recurses.
[number stream] ->(n) [cull] ->(p) [right]
After the first call right is reading primes from cull and writing them to the real stdout. cull reads candidates from the number stream and writes primes to right.
When the number stream loop ends the process ends and closes its pipe to cull. Once all the numbers have been read from the pipe, cull to reads EOF ending its loop and its process, closing its pipe to right. right reads EOF and returns back to main which exits.
To explain redirect we need to understand redirection in C.
First, a simple one-way pipe.
int pd[2];
pipe(pd);
//parent
if (fork()) {
// Parent must close the input side else reading from pd[0] will
// continue to try to read from pd[1] even after the child closes
// their pipe.
close(pd[1]);
int p;
while( read(pd[0], &p, sizeof(p)) ) {
printf("p = %d\n", p);
}
fprintf(stderr, "parent done reading\n");
}
// child
else {
// Not strictly necessary, but the child will not be reading.
close(pd[0]);
for (int i = 2; i < 10; i++) {
write(pd[1], &i, sizeof(i));
}
// Tell the parent we're done writing to the pipe.
// The parent will get EOF on its next read. If the child
// does not close the pipe, the parent will hang waiting to read.
close(pd[1]);
fprintf(stderr, "child done writing\n");
// Pipes are closed automatically when a process exits, but
// let's simulate the child not immediately exiting to
// illustrate why it's important to explicitly close pipes.
sleep(1);
}
The parent and child share a pipe. The parent reads from one end, the child writes to the other. The child closes their write end when they're done so the parent doesn't hang trying to read. The parent closes their write end immediately so their pipe doesn't try to read from it.
Instead of passing the pipe around, redirect is redirecting the parent's half to stdin and the child's half to stdout. Let's do that in our simple example using dup2. dup2 duplicates a descriptor to another, first closing the target.
int pd[2];
pipe(pd);
if (fork()) {
// Redirect pd[0] to stdin.
dup2(pd[0], STDIN_FILENO);
// Parent still has to close its input side.
close(pd[1]);
int p;
while( read(STDIN_FILENO, &p, sizeof(p)) ) {
printf("p = %d\n", p);
}
fprintf(stderr, "parent done reading\n");
} else {
// Redirect pd[1] to stdout.
dup2(pd[1], STDOUT_FILENO);
// Close the original pd[1] so the parent doesn't try to read from it.
close(pd[1]);
for (int i = 2; i < 10; i++) {
write(STDOUT_FILENO, &i, sizeof(i));
}
// Tell the parent we're done writing.
close(STDOUT_FILENO);
fprintf(stderr, "child done writing\n");
sleep(1);
}
The final twist is dup. dup duplicates pd[k] to the lowest numbered descriptor currently not in use by the process. redirect(0, pd) closes descriptor 0 and then copies pd[0] to the lowest numbered descriptor: 0.
redirect(1, pd) closes descriptor 1 and then copies pd[1] to what it hopes is the lowest numbered descriptor: 1. If something else closed 0, redirect(1, pd) will copy pd[1] to descriptor 0 and the code will not work. This can be avoided by using dup2 which makes it explicit which file descriptor you're copying to.
// close(k) and dup(pd[k]) to k safely and explicitly.
dup2(pd[k], k);
redirect can be rewritten as:
void redirect(int k, int pd[]) {
dup2(pd[k], k);
close(pd[0]);
close(pd[1]);
}
Note that is all for a one-way pipe. cull uses bi-directional pipes, but the idea is the same.
By redirecting its pipe to stdin and stdout the program can use the pipe without having to pass the pipe around. This lets right read the first prime from the number generator and then let cull read the rest. It could also be done explicitly.
With some simpler examples in place, now we can answer the questions.
1). Why does redirect need to close pd[1]?
The parent must close the input side of its pipe, even after it's been duplicated or closed by the child, else the pipe will remain open and the parent will hang trying to read from it.
cull() is reading from the file descriptor 0, but in right() the child process will close 0. Why doesn't this cause any problem?
right closes its 0 and then copies pd[0] to 0. cull does not close 0, it closes pd[0]. cull reads from the original 0 which is the number generator.
Why it is necessary to use redirect here when we only want read from 0 and write to 1?
Because we need 0 and 1 to be different things at different times. We don't really want to read from 0 and write to 1. We want to read and write from pipes which happen to be attached to 0 and 1. The program is redirecting its pipes to 0 and 1 to demonstrate how Unix pipes and redirection works internally.
It took a dabbler like me some time to figure out how this program worked, it would have been a lot easier if I'd read the original paper and seen the shell script version first.
It can be rewritten to use explicit pipes. This avoids action at a distance, is easier to understand, and still demonstrates pipes and co-routines, but it no longer illustrates redirection.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void cull(int p, int read_d, int write_d) {
int n;
while (read(read_d, &n, sizeof(n))) {
if (n % p != 0) {
write(write_d, &n, sizeof(n));
}
}
}
void right(int read_d) {
int p;
if (read(read_d, &p, sizeof(p))) {
printf("prime %d\n", p);
int cull_pipe[2];
pipe(cull_pipe);
if (fork()) {
// right() reads from cull().
close(cull_pipe[1]);
right(cull_pipe[0]);
} else {
// cull() reads from the number generator and writes to right().
close(cull_pipe[0]);
cull(p, read_d, cull_pipe[1]);
close(cull_pipe[1]);
}
}
}
int main(int argc, char *argv[]) {
int pd[2];
pipe(pd);
if (fork()) {
// The first call to right() reads from the number generator.
close(pd[1]);
right(pd[0]);
} else {
close(pd[0]);
for (int i = 2; i < 6; i++) {
write(pd[1], &i, sizeof(i));
}
close(pd[1]);
}
exit(0);
}
Other notes:
The headers can be replaced with standard headers.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
Here is a C program which operates finding specific properties like CPU bus info by consecutive calls of lshw (to access total hardware list with respective properties) and grep (to select just a relevant point among lshw results):
char *strCombine(char *str1, char *str2, int n)
{
int i = strlen(str2);
int j = 0;
if((str2 = (char *) realloc(str2, (i + n + 1))) == NULL)
perror(0);
while(j < n && str1[j])
{
str2[i] = str1[j];
i++;
j++;
}
str2[i] = 0;
return (str2);
}
int main()
{
pid_t parent;
char buf[1000] = {0};
char *str;
char *argv[6] = {"/usr/bin/lshw", "-C", "CPU", "|", "grep", "bus info"};
int fd[2];
int ret;
if(pipe(fd) == -1)
{
perror(NULL);
return -1;
}
parent = fork();
if(parent == 0)
{
close(fd[1]);
while((ret = read(fd[0], buf, 1000)))
str = strCombine(buf, str, ret);
close(fd[0]);
}
else
{
close(fd[0]);
execv(argv[0], argv);
close(fd[1]);
wait(0);
}
wait(0);
printf("%s", str);
return 0;
}
In this code grep is expected to follow lshw since both go executed by invoking execv. However, this pipeline doesn't work because lshw usage reference gets printed out in terminal (running on Ubuntu 18.04 LTS) instead of bus info needed originally. What makes this program failed to show just info that matters and what way must I try to set up pipeline?
The vertical bar is not a parameter you use to separate commands, as the execve(2) system call will load a program into the virtual space of one process only. You need to create two processes, one per command you want to execute, and communicate them so input from one goes to output from the other. I think also you'll be interested in the output of the last command, so you need to do two redirections (one from the first command to the second, and one from the output of the second command to a pipe descriptor), two forks, and two exec's in order to do this.
First the good news, you can do all this stuff with a simple call to popen(3) without the nitty gritties of making forks and execs while redirecting i/o from individual commands. Just use this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "/usr/bin/lshw -C CPU | grep 'bus info'";
int n = 0;
char line[1000];
/* f will be associated to the output of the pipeline, so you can read from it.
* this is stated by the "r" of the second parameter */
FILE *f = popen(cmd, "r");
if (!f) {
perror(cmd);
exit(EXIT_FAILURE);
}
/* I read, line by line, and process the output,
* printing each line with some format string, but
* you are free here. */
while (fgets(line, sizeof line, f)) {
char *l = strtok(line, "\n");
if (!l) continue;
printf("line %d: [%s]\n", ++n, l);
}
/* once finished, you need to pclose(3) it. This
* makes program to wait(2) for child to finish and
* closing descriptor */
pclose(f);
}
If you need to mount such a pipeline you'll end having to
redirections from first command to second, from second to
parent process, and fork/exec both processes yourself.
In this approach, you handle a subshell to do the piping
and redirection work for you, and just you get a FILE * descriptor to read upon.
(if I find some time, I'll show you a full example of a chain of N commands with redirections to pipe them, but I cannot promise, as I have to write the code)
NOTE
fork() returns the pid of the child process to the parent, and 0 to the child process itself. I don't understand why you have a variable named parent where you store the value received from fork(). If it is nonzero (and non-negative) it represents the pid of a child process. You need two, as you need two processes. In the example I post, you create three processes (you ask a subshell to mount the pipeline for you, so you have a subshell you instruct to create two more processes, to execute your command) If you had to mount all this paraphernalia, you'd also to wait(2) for the children to finish (this is done in pclose(3) call)
I have a little program to spawn a process (only one) repeatedly, while overprinting its output in the same place. I use it as some kind of htop program when I try to see e.g. the output of ls -l (showing a file growing as it is being filled) or the output of df command. It starts the program, makes one fork, redirects the output of it to a pipe and gets the output of the command to count the number of lines output (to emit an escape sequence to put the cursor on top of the listing, and to emit a clear to the end of line after each output line, so shorter lines dont get blurred by longer ones. It shows you how to deal with forks and exec system calls, and you can use as example on how to do the things the brave way. But having popen(3) I think is the solution to your problem. If you want to have a look to my cont program, just find it here.
There are many questions related to reading and writing of pipes in this forum, but i am unable to resolve my issue.
The code snippet below, does the following things:
Through command line argument filename is passed to the child process through pipe_p
Child process opens the file specified, and writes its content to pipe_c for parent process to read and display on the screen.
Everything is working fine, but parent process is unable to read data from the pipe (since it is not printing anything).
I observed that data is successfully written by child process since i am able to print the contents through pipe in child process block but not in parent process.
NOTE : STEP 4 is not working
Anyone please help me this.
Code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
int pipe_p[2], pipe_c[2];
int childpid, c, k = 0;
char buffer[1000] = {0};
FILE *file;
pipe(pipe_p);
pipe(pipe_c);
childpid = fork();
if(childpid){
//parent process block
//STEP 1 -------
close(pipe_p[0]); //closing reading side of pipe
write(pipe_p[1], argv[1], strlen(argv[1]));
close(pipe_p[1]);
//--------------
wait(NULL);
//--------------
//printf("%s\n", "Its working");
//STEP 4 -------
close(pipe_c[1]);
read(pipe_c[0], buffer, sizeof(buffer));
close(pipe_c[0]);
printf("%s\n", buffer);
//--------------
}
else{
//child process block
//sleep(1);
//STEP 2 -------
close(pipe_p[1]);
read(pipe_p[0], buffer, sizeof(buffer));
close(pipe_p[0]);
//printf("%s\n", buffer);
//--------------
//STEP 3 -------
file = fopen(buffer, "r");
while((c = getc(file)) != EOF){
buffer[k++] = c;
}
buffer[k] = 0;
//printf("%s", buffer);
close(pipe_c[0]);
write(pipe_c[1], buffer, strlen(buffer));
close(pipe_c[1]);
//--------------
}
return 0;
}
I see five bugs in this code. I'm going to list them from least to most important. I haven't tried to fix any of the bugs, so there may be more that are hidden behind these.
You forgot to include sys/wait.h. The compiler should have complained about an implicit declaration of wait. (If your compiler did not make any complaints, turn on all the warnings.)
You are not checking whether any of your system calls are failing. Every system call should be followed by a check for failure. When one does fail, print to stderr a full description of the failure, including the name of the system call that failed, the names of all files involved (if any), and strerror(errno) and then exit the program with a nonzero (unsuccessful) exit code. If you had done this you would have discovered for yourself that, in fact, certain things were not "working fine".
Relatedly, you are not checking whether the child exited unsuccessfully. Instead of wait(NULL), the parent should be doing waitpid(childpid, &status, 0) and then decoding the exit status and printing a message to stderr for anything other than WIFEXITED(status) && WEXITSTATUS(status) == 0 and then exiting unsuccessfully itself.
In the parent, you are calling wait in the wrong place. You need to call wait AFTER you have read and processed all of the data from pipe_c. Otherwise, if the child process completely fills up the pipe buffer, the program will deadlock. (Also, you need to read all of the data from the pipe, not just the first 1000 bytes of it.)
In the child, you have a buffer overrun. You are reading an unlimited amount of data from the file into buffer, but buffer has a fixed size. You should either use malloc and realloc to enlarge it as necessary, or copy from the file to the pipe in chunks no bigger than the size of buffer.
I discovered all of these problems by running the program under the strace utility, in -f mode (so it traces both sides of the fork), with input from a large file. This is a valuable debugging technique which you should try for yourself.
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 have written client-sever code where I have many connections, let say each node represents different process on same machine. And to do that I have obviously use fork().
But now problem is that all results get displayed on same terminal.
I want to know is there any way such that after each fork() or process creation new terminal gets opened and all results get displayed for that process on particular terminal.
P.S: I have tried system("gnome-terminal") but it just opens new terminal but all results get displayed again on same terminal only. All new terminals are just opens and remain blank without any result.
Also I have gone through this link How to invoke another terminal for output programmatically in C in Linux but I don't want to run my program with parameters or whatever. Its should be just like ./test
Here is my code:-
for(int i=0;i<node-1;i++)
{
n_number++;
usleep(5000);
child_pid[i]=fork();
if(!child_pid[i])
{
system("gnome-terminal");
file_scan();
connection();
exit(0);
}
if(child_pid[i]<0)
printf("Error Process %d cannot be created",i);
}
for(int i=0;i<node-1;i++)
wait(&status);
So basically what I want is for each process there should be new terminal displaying only that process information or result.
What I exactly want:
After fork() I have some data related to say process 1 then I want its output to one terminal
Same goes with each process. So its like if I have 3 process then there must be 3 terminals and each must display process related data only.
I know it can be doable using IPC(Inter Process Communication) but is there any other way around? I mean just 2-3 commands or so? Because I do not want to invest too much in coding this part.
Thanks in advance!!!
Maybe you want something like that. This program is using the unix98 pseudoterminal (PTS), which is a bidirectional channel between master and slave. So, for each fork that you do, you will need to create a new PTS, by calling the triad posix_openpt, grantpt, unlockpt at master side and ptsname at slave side. Do not forget to correct the initial filedescriptors (stdin, stdout and sdterr) at each side.
Note that is just a program to prove the concept, so I am not doing any form of error check.
#define _XOPEN_SOURCE 600
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <fcntl.h>
int main() {
pid_t i;
char buf[10];
int fds, fdm, status;
fdm = posix_openpt(O_RDWR);
grantpt(fdm);
unlockpt(fdm);
close(0);
close(1);
close(2);
i = fork();
if ( i != 0 ) { // father
dup(fdm);
dup(fdm);
dup(fdm);
printf("Where do I pop up?\n");
sleep(2);
printf("Where do I pop up - 2?\n");
waitpid(i, &status, 0);
} else { // child
fds = open(ptsname(fdm), O_RDWR);
dup(fds);
dup(fds);
dup(fds);
strcpy(buf, ptsname(fdm));
sprintf(buf, "xterm -S%c/2", basename(buf));
system(buf);
exit(0);
}
}