How to open new terminal through C program in linux - 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);
}
}

Related

C program cannot use pipe to execute the "more" command in "execlp" in order to view program's output

thanks in advance for any help.
I am trying to replicate the behavior of the shell command ls -1 /usr/include | more using a C program.
I wrote this code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int page[2]; // page is the name of my pipe
pipe(page);
switch (fork()){
case -1:
exit(1);
break;
case 0:;
close(page[1]);
dup2(page[0], 0);
close(page[0]);
execlp("more", "more", NULL);
default:
close(page[0]);
dup2(page[1], 1);
close(page[1]);
execlp("ls", "ls", "-1", "/usr/include", NULL);
break;
}
}
But it only prints one page (as more would do) and causes some weird behavior that blocks my terminal (forcing me to use reset to set it back to normal).
Your original code creates a kind of a race condition between the parent and the child processes, and the shell which started your program. The ls process ends before more can read all the data from the pipe, and since in your program the parent process is replaced by the ls process, when that ls process ends (after writing all its output into the pipe buffer) it exits, and in doing so closes the pipe and gives control back to the shell which will immediately get ready to read another command.
So, initially both more and the shell may be reading from the same TTY device (it's reading from its STDERR descriptor, still attached to your TTY), and then once more eventually gets some input it will try to read from the pipe again (its STDIN) and it will get an end-of-file (the pipe has been closed on the write end by the exit of ls), and so more will now also exit (without printing any more output). There's also a possible race between the more process and the shell as to which (re)sets the TTY driver modes and when.
An alternative implementation of your program is for the original parent process to start two child processes, one for more and one for ls, and then to wait for both processes to terminate, but this will of course require more system resources.
I just realized the roles of the parent and the child process were being mixed up. The one to run the more command should be the parent. Since more is an interactive command, the terminal will respond better to it as the parent (I'm guessing).
So to solve my issue, I switched the roles of the parent and the child.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int page[2]; // page is the name of my pipe
pipe(page);
switch (fork()){
case -1:
exit(1);
break;
case 0:;
close(page[0]);
dup2(page[1], 1);
close(page[1]);
execlp("ls", "ls", "-1", "/usr/include", NULL);
break;
default:
close(page[1]);
dup2(page[0], 0);
close(page[0]);
execlp("more", "more", NULL);
}
}
WHY DOES THIS SOLVES THE PROBLEM? (I still do not clearly understand why it worked!)

C homework with pipes and forks [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Hello everyone,
I'm quite lost in my school homework since they haven't told us much about it and I haven't done anything like that before.
The task is:
In the C language create a program that creates two processes (fork function) and connects them via pipe (the pipe function).
The first descendant redirects its' stdout into the pipe and writes (space separated) pairs of random numbers into it (function rand).
Delay the output of the numbers (i.e. by 1 second).
The first descendant has
to treat the SIGUSR1 signal (sigaction function) and in case of receiving such signal it prints a string “TERMINATED” to it's stderr and terminates.
The second descendant redirects the pipe output to it's stdin, redirects it's stdout into a file called out.txt in
the current directory and executes a binary file (execl function) for finding the greatest common divisor (the output of our previous tasks where we had to write a makefile that runs a small C program that detects if a number is prime).
The parent process waits 5 seconds and then sends SIGUSR1 to the first process (number generator). This should perform a correct termination of both processes. It waits for the sub-processes to terminate (wait function) and terminates itself.
In fact you are implementing something like this: while : ; do echo $RANDOM $RANDOM ; sleep 1; done | ./c1_task > out.txt
I'm absolutely lost in this and I have nothing so far unfortunatelly.
I don't know where to start.
Could somebody advise me something, please?
Thanks in advance!
Since I don't believe in doing people's work for them, I can't give you the "solution." I can, however, show you some of the concepts that you need to know to fulfill your assignment. I can also give you a couple of links, but if you just search for help with the concepts you don't understand, you're likely to find the information you need anyways.
Now that I've delivered a paragraph of introductory information, I'm going to work you through some of the concepts you need to understand to solve this problem.
I may fill in some missing information if I get (and feel like it's worth spending) the time necessary to turn this into a pseudo-tutorial. :)
The information provided may be simplified, a little vague, or otherwise open to improvement. Feel free to let me know if you, dear reader, spot a problem.
First Concept: fork()-ing
What is it? fork() makes it easy to do multiple things simultaneously by duplicating (much of) the current process into another process. (Actually, it is similar to asexual reproduction.)
For instance, the child process (this is the new process that was created by making the fork() system call) inherits open file descriptors (this is an important point!), has its own copy of variables that the parent process (has/had), etc.
Example: Here's an example program that illustrates a thing or two. Note the wait(). It makes the parent, the process that called fork(), wait to continue executing the rest of the program until a child has terminated. Without wait(NULL), we can't guarantee that the parent's printf statement will run after the child's printf statement.
#include <stdio.h> //the usual, perror
#include <stdlib.h> //exit
#include <sys/types.h> //wait() / pid_t
#include <sys/wait.h> //wait()
#include <unistd.h> // fork()
int main () {
pid_t cpid;
//create our child.
//fork() returns -1 if the fork failed, otherwise it returns
// the pid of the child to the parent,
// and 0 to the child
cpid = fork();
//Both the child process and parent process executed the
//"cpid =" assignment.
//However, they both modified their own version of cpid.
//From now on, everything is run by both the child and parent.
//the fork failed; there is no child so we're done.
if (cpid < 0) {
perror("During attempted fork");
exit(EXIT_FAILURE);
}
//Though the if statement will be checked by both,
//cpid will equal 0 only in the child process.
if (cpid == 0) {
//This will be executed by the child.
printf("Hello. I'm your child.\n");
//Now that we've let Pops know that we're alive...
exit(EXIT_SUCCESS);
}
else if (cpid > 0) {
//wait for our child to terminate.
//I dare you to comment this out & run the program a few times.
//Does the parent ever print before the child?
wait(NULL);
printf("I proudly parented 1 child.\n");
}
return 0;
}
Other: You can see another example here.
Second concept: Pipes
What is a pipe? A pipe is a method for interprocess communication. Basically, it has one end that data can be put in (write() is one way to do it) and one end that data can be gotten out of (using read).
Pipes are created using the pipe() system call. It returns -1 on error. It's only argument is the address of an array of two ints, which we'll call pipe_fds.
If the call succeeded, the first element in pipe_fds contains the file descriptor that is used to read from the pipe; the second element contains the file descriptor used to write to the pipe.
You can write to the pipe with write() and read from the pipe with read(). (More info about using pipes can be found at various places on the internet.
Here's an example:
#include <stdio.h> //the usual, perror
#include <stdlib.h> //exit
#include <sys/types.h> //wait() / pid_t
#include <sys/wait.h> //wait()
#include <unistd.h> // fork(), pipe()
#define BUFLEN 256 //must be greater than one
int main () {
int pipe_fds[2],
pipe_ret;
pid_t cpid;
//Let's create a pipe.
//Note that we do this *before* forking so that our forked child
// has access to the pipe's file descriptors, pipe_fds.
pipe_ret = pipe(pipe_fds);
//we couldn't create our pipe
if (pipe_ret == -1) {
perror("Pipe Creation");
exit(EXIT_FAILURE);
}
//create our child.
cpid = fork();
//the fork failed; there is no child so we're done.
if (cpid < 0) {
perror("During attempted fork");
exit(EXIT_FAILURE);
}
//Am I the child?
if (cpid == 0) {
//close the childs read end of the pipe.
//Failing to close unused pipe ends is life or death!
//(Check `man 7 pipe`)
close(pipe_fds[0]);
//Send a message through the pipe.
//NOTE: For simplicity's sake, we assume that our printing works.
// In the real world, it might not write everything, etc.
//We could use `write()`, but this way is easier.
dprintf(pipe_fds[1], "Daddy, I'm alive.\n");
//We're done writing. Close write end of the pipe.
//This is the wise thing to do, but it would get closed anyways.
close(pipe_fds[1]);
//Now that we've let Pops know that we're alive...
exit(EXIT_SUCCESS);
}
else if (cpid > 0) {
char buf[BUFLEN] = {};
int bytes_read = 0;
//close *our* write end of the pipe. Important!
//Comment this out and watch your program hang.
//Again, check out `man 7 pipe`.
close(pipe_fds[1]);
//read data from pipe until we reach EOF
while ((bytes_read = read(pipe_fds[0], buf, BUFLEN - 1)) > 0) {
//null terminate our string.
//(We could use snprintf instead...)
buf[bytes_read] = '\0';
//You can comment this out to prove to yourself that
//we're the one printing the child's message.
printf("%s", buf);
}
//close read end of pipe
close(pipe_fds[0]);
//wait for our child to terminate.
wait(NULL);
printf("I proudly parented 1 child.\n");
}
return 0;
}
As you can see, I just gave a small tutorial on two of the concepts you need to know to finish your assignment. I need some sleep, so I'll leave it at that for tonight.
Read and experiment with the examples! Notes in the comments are to help you learn.

error in executing system function with STDOUT_FILENO closed

I have an strange issue. I am not very good in C language. I am trying to create a daemon to execute my bash script based service in Linux. To make it easy I have made the code simple. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>
int main(int argc, char* argv[])
{
pid_t process_id = 0;
pid_t sid = 0;
process_id = fork();
if (process_id < 0)
{
printf("fork failed!\n");
exit(1);
}
if (process_id > 0)
{
printf("daemon creatd with process id %d \n", process_id);
exit(0);
}
umask(0);
sid = setsid();
if(sid < 0)
{
fprintf(stderr, "Return error\n");
exit(1);
}
chdir("/");
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
int status = system("ls");
openlog("slog", LOG_PID|LOG_CONS, LOG_USER);
syslog(LOG_INFO, "Returned status is %d", status);
closelog();
return (0);
}
As you can see, the above program will execute the system function to execute the ls command and output the exit code to system log.
After I compile the program and run, in the logs I can see the status code is 512. But If I comment out the following line,
close(STDOUT_FILENO);
then it works perfect and I can see in the log the status code is 0,
What I might be doing wrong?
UPDATE
My program is pretty big and I am not using ls in real environment. i made the program simple to reproduce the issue what I am facing. Also, to see the status of program, I am not looking at the output but the status code in the syslog.
In case it is not clear from other comments and answers, ls writes its output to stdout. If it can not write to stdout it terminates and (apparently) sets an status code of 512 (non-zero in any case).
The child process will inherit stdout from the parent, so if you do not close stdout in the parent, the child will have a stdout to write to and the command will succeed. If you close stdout, then the child has nowhere to write its output and the error occurs.
So, although ls is just an example for this question, your actual child process is writing to stdout which results in the same problem.
The simplest way around this, and assuming that you do not want the child's output, is to redirect the child's stdout on the command line:
int status = system("ls >/dev/null 2>&1");
This will redirect stdout and stderr to /dev/null, effectively throwing away the child's output while still giving it somewhere to write to.
Your daemon creation looks fine. But daemon processes by convention do not have a controlling terminal which you accomplish by closing all the standard file descriptors and call setsid() to create a new session to make the daemon a session leader. So, you can't make the daemon produce any output on the stdout stream. It obviously works if you don't close the stdout stream.
So, what you are doing is trying to write something to a tty from a terminal. So, you either don't need a daemon for this purpose or you need to write to a different file (instead of stdout).

Can a single pipe be used for 2 way communication between parent and a child?

Suppose I use pipefdn[2] and pipe() on it , can bidirectional communication be implemented using a single pipe or do you need 2 pipes ?
Though this operation results as success in some cases, but it is not a recommended way , especially in the production code. As pipe() by default dont provide any sync mechanism and moreover the read() can go for an infinite hang, if no data or read() is called before write() from other process.
Recommended way is to always use 2 pipe. pipe1[2], pipe2[2] for two way communication.
For more info please refer the following video description.
https://www.youtube.com/watch?v=8Q9CPWuRC6o&list=PLfqABt5AS4FkW5mOn2Tn9ZZLLDwA3kZUY&index=11
No sorry. Linux pipe() is unidirectional. See the man page, and also pipe(7) & fifo(7). Consider also AF_UNIX sockets, see unix(7).
Correct me if I am wrong: But I think you can. The problem is that you probably don't want to do that. First, of all create a simple program:
#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int pd[2];
int num = 2;
int main(){
pid_t t = fork();
/* create a child process */
if(t<0){
printf("error in fork");
exit(1);
}
/* create a pipe */
if(pipe(pd)==-1){
printf("error in pipe");
exit(3);
}
else if(t==0){
//close(pd[1]); // child close writing end
int r = read(pd[0], &num, sizeof(num));
if(r<0){
printf("error while reading");
exit(2);
}
printf("i am the child and i read %d\n",num);
// close(pd[0]);
exit(0);
}
/* parent process */
//close(pd[0]); /* parents closes its reading end
if(write(pd[1],&num,sizeof(num)<0)){
printf("error in reading");
exit(4);
}
//close(pd[1]);
/*parent wait for your child to terminate;*/
int status;
wait(&status);
printf("my child ended with status: %d\n",status);
return 0;
}
Try to play with close(). Skip it by putting it in a comment or include it. You will find out that in order this program to run the only really needed system-call close is the one before the child reads. I found here in stack overflow an answer saying that " Because the write-end is open the system waits because a potential write could occur .. " . Personally, I tried to run it without it and I discovered that it would not terminate. The other close(), although are a good practice , don't influence the execution. ( I am not sure why that happens maybe someone more experienced can help us).
Now let's examine what you asked:
I can see some problems here:
If two processes write in the same channel you may have race conditions:
They write to the same file descriptor at the same time:
What if one process reads its own writings instead of those of the process
it tries to communicate with? How you will know, where in the file you should read?
What if the one process, writes "above" the writings of the other?
Yes it can, I've done that before. I had a parent and child send each other different messages using the same 2 pipes and receive them correctly. Just make sure you're always reading from the first file descriptor and writing to the second.

Dead lock linux pipe

I want to learn how Linux pipes work! I wrote a small and easy program that use a pipe to communicate a string between parent and child process. However, the program results in a dead lock that I have not understood what is its cause.
Here is the code :
#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define SIZE 100
int
main(int argc, char *argv[])
{
int pfd[2];
int read_pipe=0, write_pipe=0;
pid_t cpid;
char buf[SIZE];
/* PIPE ***************************************
* pipe() creates a pair of file descriptors, *
* pointing to a pipe inode, and places them *
* in the array pointed to by filedes. *
* filedes[0] is for reading, *
* filedes[1] is for writing *
**********************************************/
if (pipe(pfd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
read_pipe=pfd[0];
write_pipe=pfd[1];
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
char * hello = "I am a child process\n";
sleep(1);
// wait until there is some data in the pipe
while (read(read_pipe, buf, SIZE) > 0);
printf("Parent process has written : %s\n", buf);
write(write_pipe, hello, strlen(hello));
close(write_pipe);
close(read_pipe);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
char * hello = "I am a parent process\n";
write(write_pipe, hello, strlen(hello));
while (read(read_pipe, buf, SIZE) > 0);
printf("Child process has written : %s\n", buf);
close(write_pipe);
close(read_pipe);
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
In this link you'll find the proper mannipulation of PIPEs between parent and child. Your problem here is that the communication is not being correctly set-up.
The PIPE should be used to communicate in only one direction, so one process has to close the read descriptor and the other has to close the write descriptor. Otherwise what will happen is that the call to 'read'(both on the father and the son), since it can detect that there is another process with an open write descriptor on the PIPE, will block when it finds that the PIPE is empty (not return 0), until someone writes something in it. So, both your father and your son are getting blocked on their respective read.
There are two solutions to this:
.You create two PIPEs, one for the communication in each direction, and perform the initialization as explained in the link above. Here you have to remember to close the write descriptor when you are done sending the message, so the other process' read will return, or condition the loop to the count of bytes read (not to the return of read), so you won't perform another call when you read the whole message. For example:
int bread = 0;
while(bread < desired_count)
{
bread += read(read_pipe, buf + bread, SIZE - bread);
}
.You create one PIPE as you did, and modify the flags on the read descriptor, using fcntl to also have O_NONBLOCK, so the calls to read won't block when there's no information in the PIPE. Here you need to check on the return value of the read to know you received something, and go adding up until you get the full length of the message. Also you will have find a way to synchronize the two processes so they won't read messages that are not meant for them. I don't recommend you to use this option, but you can try it if you want using condition variables.
Maybe you can tell if you see any of yout printf() outputs?
Anyway, if you want to establish a two way communication between your paent and child, yout should use two pipes, one for writing data form parent to child an the other for writing from child to parent. Furthermore, your read loops may be dangerous: if the data comes in two or more chunks the second read() overwrites the first portion (I've never seen tha happen with local pipes, but for example with sockets). And of course, yout is not automatically null terminated after read(), so just printing int with "%s" may also cause problems.
I hope that gives you some ideas to try.

Resources